Vladimir Makarov <vmaka...@redhat.com> writes:
> This is the major patch containing all new files.  The patch also adds 
> necessary calls to LRA from IRA.As the patch is too big, it continues in 
> the next email.
>
> 2012-09-27  Vladimir Makarov  <vmaka...@redhat.com>
>
>      * Makefile.in (LRA_INT_H): New.
>      (OBJS): Add lra.o, lra-assigns.o, lra-coalesce.o,
>      lra-constraints.o, lra-eliminations.o, lra-lives.o, and lra-spills.o.
>      (ira.o): Add dependence on lra.h.
>      (lra.o, lra-assigns.o, lra-coalesce.o, lra-constraints.o): New entries.
>      (lra-eliminations.o, lra-lives.o, lra-spills.o): Ditto.
>      * ira.c: Include lra.h.
>      (ira_init_once, ira_init, ira_finish_once): Call lra_start_once,
>      lra_init, lra_finish_once in anyway.
>          (lra_in_progress): Remove.
>      (do_reload): Call LRA.
>      * lra.h: New.
>      * lra-int.h: Ditto.
>      * lra.c: Ditto.
>      * lra-assigns.c: Ditto.
>      * lra-constraints.c: Ditto.
>      * lra-coalesce.c: Ditto.
>      * lra-eliminations.c: Ditto.
>      * lra-lives.c: Ditto.
>      * lra-spills.c: Ditto.
>      * doc/passes.texi: Describe LRA pass.

Comments on ira-lives.c.  (Sorry for the split, had more time to look
at this than expected)

> +/* Copy live range list given by its head R and return the result.  */
> +lra_live_range_t
> +lra_copy_live_range_list (lra_live_range_t r)
> +{
> +  lra_live_range_t p, first, last;
> +
> +  if (r == NULL)
> +    return NULL;
> +  for (first = last = NULL; r != NULL; r = r->next)
> +    {
> +      p = copy_live_range (r);
> +      if (first == NULL)
> +     first = p;
> +      else
> +     last->next = p;
> +      last = p;
> +    }
> +  return first;
> +}

Maybe simpler as:

  lra_live_range_t p, first, *chain;

  first = NULL;
  for (chain = &first; r != NULL; r = r->next)
    {
      p = copy_live_range (r);
      *chain = p;
      chain = &p->next;
    }
  return first;

> +/* Merge ranges R1 and R2 and returns the result.  The function
> +   maintains the order of ranges and tries to minimize size of the
> +   result range list.  */
> +lra_live_range_t 
> +lra_merge_live_ranges (lra_live_range_t r1, lra_live_range_t r2)
> +{
> +  lra_live_range_t first, last, temp;
> +
> +  if (r1 == NULL)
> +    return r2;
> +  if (r2 == NULL)
> +    return r1;
> +  for (first = last = NULL; r1 != NULL && r2 != NULL;)
> +    {
> +      if (r1->start < r2->start)
> +     {
> +       temp = r1;
> +       r1 = r2;
> +       r2 = temp;
> +     }
> +      if (r1->start <= r2->finish + 1)
> +     {
> +       /* Intersected ranges: merge r1 and r2 into r1.  */
> +       r1->start = r2->start;
> +       if (r1->finish < r2->finish)
> +         r1->finish = r2->finish;
> +       temp = r2;
> +       r2 = r2->next;
> +       pool_free (live_range_pool, temp);
> +       if (r2 == NULL)
> +         {
> +           /* To try to merge with subsequent ranges in r1.  */
> +           r2 = r1->next;
> +           r1->next = NULL;
> +         }
> +     }
> +      else
> +     {
> +       /* Add r1 to the result.  */
> +       if (first == NULL)
> +         first = last = r1;
> +       else
> +         {
> +           last->next = r1;
> +           last = r1;
> +         }
> +       r1 = r1->next;
> +       if (r1 == NULL)
> +         {
> +           /* To try to merge with subsequent ranges in r2.  */
> +           r1 = r2->next;
> +           r2->next = NULL;
> +         }
> +     }

I might be misreading, but I'm not sure whether this handles merges like:

  r1 = [6,7], [3,4]
  r2 = [3,8], [0,1]

After the first iteration, it looks like we'll have:

  r1 = [3,8], [3,4]
  r2 = [0,1]

Then we'll add both [3,8] and [3,4] to the result.

Same chain pointer comment as for lra_merge_live_ranges.

> +/* Return TRUE if live range R1 is in R2.  */
> +bool
> +lra_live_range_in_p (lra_live_range_t r1, lra_live_range_t r2)
> +{
> +  /* Remember the live ranges are always kept ordered.       */
> +  while (r1 != NULL && r2 != NULL)
> +    {
> +      /* R1's element is in R2's element.  */
> +      if (r2->start <= r1->start && r1->finish <= r2->finish)
> +     r1 = r1->next;
> +      /* Intersection: R1's start is in R2.  */
> +      else if (r2->start <= r1->start && r1->start <= r2->finish)
> +     return false;
> +      /* Intersection: R1's finish is in R2.  */
> +      else if (r2->start <= r1->finish && r1->finish <= r2->finish)
> +     return false;
> +      else if (r1->start > r2->finish)
> +     return false; /* No covering R2's element for R1's one.  */
> +      else
> +     r2 = r2->next;
> +    }
> +  return r1 == NULL;

Does the inner bit reduce to:

      /* R1's element is in R2's element.  */
      if (r2->start <= r1->start && r1->finish <= r2->finish)
        r1 = r1->next;
      /* All of R2's element comes after R1's element.  */
      else if (r2->start > r1->finish)
        r2 = r2->next;
      else
        return false;

(Genuine question)

> +/* Process the death of hard register REGNO.  This updates
> +   hard_regs_live and START_DYING.  */
> +static void
> +make_hard_regno_dead (int regno)
> +{
> +  if (TEST_HARD_REG_BIT (lra_no_alloc_regs, regno)
> +      || ! TEST_HARD_REG_BIT (hard_regs_live, regno))
> +    return;
> +  lra_assert (regno < FIRST_PSEUDO_REGISTER);
> +  sparseset_set_bit (start_dying, regno);
> +  CLEAR_HARD_REG_BIT (hard_regs_live, regno);
> +}

Assert should be before the HARD_REG_SET stuff (like for
make_hard_regno_born).

> +       /* Check that source regno does not conflict with
> +          destination regno to exclude most impossible
> +          preferences.  */
> +       && ((((src_regno = REGNO (SET_SRC (set))) >= FIRST_PSEUDO_REGISTER
> +             && ! sparseset_bit_p (pseudos_live, src_regno))
> +            || (src_regno < FIRST_PSEUDO_REGISTER
> +                && ! TEST_HARD_REG_BIT (hard_regs_live, src_regno)))

This is probably personal preference, but I think this would be more
readable with an inline utility function (regno_live_p, or whatever).

> +/* Compress pseudo live ranges by removing program points where
> +   nothing happens.  Complexity of many algorithms in LRA is linear
> +   function of program points number.  To speed up the code we try to
> +   minimize the number of the program points here.  */
> +static void
> +remove_some_program_points_and_update_live_ranges (void)

Genuine question, but could we do this on the fly instead,
by not incrementing curr_point if the current point had no value?

I suppose the main complication would be checking cases where
all births are recorded by extending the previous just-closed live
range rather than starting a new one, in which case it's the previous
point that needs to be reused.  Hmm...

Richard

Reply via email to