Hi Peter,

Thanks for the patch! It makes much more sense to me to split those functions, 
and use them separately.

I tried to build a native arm-linuxeabihf toolchain with the patch. But I got 
the following ICE:

/home/renlin/try-new/./gcc/xgcc -B/home/renlin/try-new/./gcc/ -B/usr/local/arm-none-linux-gnueabihf/bin/ -B/usr/local/arm-none-linux-gnueabihf/lib/ -isystem /usr/local/arm-none-linux-gnueabihf/include -isystem /usr/local/arm-none-linux-gnueabihf/sys-include -fno-checking -O2 -g -O0 -O2 -O2 -g -O0 -DIN_GCC -W -Wall -Wno-narrowing -Wwrite-strings -Wcast-qual -Wno-format -Wstrict-prototypes -Wmissing-prototypes -Wold-style-definition -isystem ./include -fPIC -fno-inline -g -DIN_LIBGCC2 -fbuilding-libgcc -fno-stack-protector -fPIC -fno-inline -I. -I. -I../.././gcc -I../../../gcc/libgcc -I../../../gcc/libgcc/. -I../../../gcc/libgcc/../gcc -I../../../gcc/libgcc/../include -DHAVE_CC_TLS -o _negvdi2_s.o -MT _negvdi2_s.o -MD -MP -MF _negvdi2_s.dep -DSHARED -DL_negvdi2 -c ../../../gcc/libgcc/libgcc2.c
0x807eb3 lra(_IO_FILE*)
        ../../gcc/gcc/lra.c:2497
0x7c2755 do_reload
        ../../gcc/gcc/ira.c:5469
0x7c2c11 execute
        ../../gcc/gcc/ira.c:5653
Please submit a full bug report,
with preprocessed source if appropriate.
Please include the complete backtrace with any bug report.
See <https://gcc.gnu.org/bugs/> for instructions.
make[3]: *** [Makefile:916: _gcov_merge_icall_topn.o] Error 1
make[3]: *** Waiting for unfinished jobs....
make[3]: *** [Makefile:916: _gcov_merge_single.o] Error 1
during RTL pass: reload
../../../gcc/libgcc/libgcov-driver.c: In function 
‘gcov_sort_icall_topn_counter’:
../../../gcc/libgcc/libgcov-driver.c:436:1: internal compiler error: in 
remove_some_program_points_and_update_live_ranges, at lra-lives.c:1172
436 | }
    | ^
0x829189 remove_some_program_points_and_update_live_ranges
        ../../gcc/gcc/lra-lives.c:1172
0x829683 compress_live_ranges
        ../../gcc/gcc/lra-lives.c:1301
0x829d45 lra_create_live_ranges_1
        ../../gcc/gcc/lra-lives.c:1454
0x829d7d lra_create_live_ranges(bool, bool)
        ../../gcc/gcc/lra-lives.c:1466
0x807eb3 lra(_IO_FILE*)
        ../../gcc/gcc/lra.c:2497
0x7c2755 do_reload
        ../../gcc/gcc/ira.c:5469
0x7c2c11 execute
        ../../gcc/gcc/ira.c:5653
Please submit a full bug report,
with preprocessed source if appropriate.
Please include the complete backtrace with any bug report.
See <https://gcc.gnu.org/bugs/> for instructions.


Regards,
Renlin

On 11/12/2018 04:34 AM, Peter Bergner wrote:
Renlin, Jeff and Vlad: requests and questions for you below...

PR87899 shows another latent LRA bug exposed by my r264897 commit.
In the bugzilla report, we have the following rtl in LRA:

   (insn 1 (set (reg:SI 1 r1) (reg/f:SI 2040)))
...
   (insn 2 (set (mem/f/c:SI (pre_modify:SI (reg:SI 1 r1)
                                           (plus:SI (reg:SI 1 r1)
                                                    (const_int 12))))
                (reg:SI 1048))
           (expr_list:REG_INC (reg:SI 1 r1)))
...
   <another use of pseudo 2040>

My earlier patch now sees the reg copy in insn "1" and correctly skips
adding a conflict between r1 and r2040 due to the copy.  However, insn "2"
updates r1 and r2040 is live across that update and so we should create
a conflict between them, but we currently do not and that leads to us
assigning r1 to one of r2040's reload pseudos which gets clobbered by
the r1 update in insn "2".

The reason a conflict was never added between r1 and r2040 is that LRA
skips INOUT operands when computing conflicts and so misses the definition
of r1 in insn "2" and so never adds conflicts for it.  The reason the code
skips the INOUT operands is that LRA doesn't want to create new program
points for INOUT operands, since unnecessary program points can slow down
remove_some_program_points_and_update_live_ranges.  This was all fine
before when we had conservative conflict info, but now we cannot ignore
INOUT operands.

The heart of the problem is that the {make,mark}_*_{live,dead} routines
update the liveness, conflict and program point information for operands.
My solution to the problem was to pull out the updating of the program point
info from {make,mark}_*_{live,dead} and have them only update liveness and
conflict information.  I then created a separate function that is used for
updating an operand's program points.  This allowed me to modify the insn
operand scanning to handle all operand types (IN, OUT and INOUT) and always
call the {make,mark}_*_{live,dead} functions for all operand types, while
only calling the new program point update function for IN and OUT operands.

This change then allowed me to remove the hacky handling of conflicts for
reg copies and instead use the more common method of removing the src reg
of a copy from the live set before handling the copy's definition, thereby
skipping the unwanted conflict.  Bonus! :-)

This passes bootstrap and regtesting on powerpc64le-linux with no regressions.

Renlin, can you please verify that this patch fixes the issue you ran into?

Jeff, could you please throw this on your test builders to see whether
it exposes any problems with the patch I didn't see?

Otherwise, Vlad and Jeff, what do you think of this solution?

I'll note that I have compiled quite a few largish test cases and so far
I am seeing the same exact program points being used in the LRA rtl dump
before and after my patch.  I'm continuing to do that with more tests
to make sure I have everything working correctly.

I'll also note I took the opportunity to convert lra-lives.c over to using
the HARD_REGISTER_P and HARD_REGISTER_NUM_P convenience macros.

Peter


gcc/
        PR rtl-optimization/87899
        * lra-lives.c (start_living): Update white space in comment.
        (enum point_type): New.
        (sparseset_contains_pseudos_p): New function.
        (update_pseudo_point): Likewise.
        (make_hard_regno_live): Use HARD_REGISTER_NUM_P macro.
        (make_hard_regno_dead): Likewise.  Remove ignore_reg_for_conflicts
        handling.  Move early exit after adding conflicts.
        (mark_pseudo_live): Use HARD_REGISTER_NUM_P macro.  Add early exit
        if regno is already live.  Remove all handling of program points.
        (mark_pseudo_dead): Use HARD_REGISTER_NUM_P macro.  Add early exit
        after adding conflicts.  Remove all handling of program points and
        ignore_reg_for_conflicts.
        (mark_regno_live): Use HARD_REGISTER_NUM_P macro.  Remove return value
        and do not guard call to mark_pseudo_live.
        (mark_regno_dead): Use HARD_REGISTER_NUM_P macro.  Remove return value
        and do not guard call to mark_pseudo_dead.
        (check_pseudos_live_through_calls): Use HARD_REGISTER_NUM_P macro.
        (process_bb_lives): Use HARD_REGISTER_NUM_P and HARD_REGISTER_P macros.
        Use new function update_pseudo_point.  Handle register copies by
        removing the source register from the live set.  Handle INOUT operands.
        Update to the next program point using the unused_set, dead_set and
        start_dying sets.
        (lra_create_live_ranges_1): Use HARD_REGISTER_NUM_P macro.

Index: gcc/lra-lives.c
===================================================================
--- gcc/lra-lives.c     (revision 265971)
+++ gcc/lra-lives.c     (working copy)
@@ -83,7 +83,7 @@ static HARD_REG_SET hard_regs_live;
/* Set of pseudos and hard registers start living/dying in the current
     insn.  These sets are used to update REG_DEAD and REG_UNUSED notes
-   in the insn.         */
+   in the insn.  */
  static sparseset start_living, start_dying;
/* Set of pseudos and hard regs dead and unused in the current
@@ -96,10 +96,6 @@ static bitmap_head temp_bitmap;
  /* Pool for pseudo live ranges.        */
  static object_allocator<lra_live_range> lra_live_range_pool ("live ranges");
-/* If non-NULL, the source operand of a register to register copy for which
-   we should not add a conflict with the copy's destination operand.  */
-static rtx ignore_reg_for_conflicts;
-
  /* Free live range list LR.  */
  static void
  free_live_range_list (lra_live_range_t lr)
@@ -224,6 +220,57 @@ lra_intersected_live_ranges_p (lra_live_
    return false;
  }
+enum point_type {
+  DEF_POINT,
+  USE_POINT
+};
+
+/* Return TRUE if set A contains a pseudo register, otherwise, return FALSE.  
*/
+static bool
+sparseset_contains_pseudos_p (sparseset a)
+{
+  int regno;
+  EXECUTE_IF_SET_IN_SPARSESET (a, regno)
+    if (!HARD_REGISTER_NUM_P (regno))
+      return true;
+  return false;
+}
+
+/* Mark pseudo REGNO as living or dying at program point POINT, depending on
+   whether TYPE is a definition or a use.  If this is the first reference to
+   REGNO that we've encountered, then create a new live range for it.  */
+
+static void
+update_pseudo_point (int regno, int point, enum point_type type)
+{
+  lra_live_range_t p;
+
+  /* Don't compute points for hard registers.  */
+  if (HARD_REGISTER_NUM_P (regno))
+    return;
+
+  if (complete_info_p || lra_get_regno_hard_regno (regno) < 0)
+    {
+      if (type == DEF_POINT)
+       {
+         if (sparseset_bit_p (pseudos_live, regno))
+           {
+             p = lra_reg_info[regno].live_ranges;
+             lra_assert (p != NULL);
+             p->finish = point;
+           }
+       }
+      else /* USE_POINT */
+       {
+         if (!sparseset_bit_p (pseudos_live, regno)
+             && ((p = lra_reg_info[regno].live_ranges) == NULL
+                 || (p->finish != point && p->finish + 1 != point)))
+           lra_reg_info[regno].live_ranges
+             = create_live_range (regno, point, -1, p);
+       }
+    }
+}
+
  /* The corresponding bitmaps of BB currently being processed.  */
  static bitmap bb_killed_pseudos, bb_gen_pseudos;
@@ -232,7 +279,7 @@ static bitmap bb_killed_pseudos, bb_gen_
  static void
  make_hard_regno_live (int regno)
  {
-  lra_assert (regno < FIRST_PSEUDO_REGISTER);
+  lra_assert (HARD_REGISTER_NUM_P (regno));
    if (TEST_HARD_REG_BIT (hard_regs_live, regno))
      return;
    SET_HARD_REG_BIT (hard_regs_live, regno);
@@ -247,19 +294,15 @@ make_hard_regno_live (int regno)
  static void
  make_hard_regno_dead (int regno)
  {
-  lra_assert (regno < FIRST_PSEUDO_REGISTER);
-  if (! TEST_HARD_REG_BIT (hard_regs_live, regno))
-    return;
-  sparseset_set_bit (start_dying, regno);
+  lra_assert (HARD_REGISTER_NUM_P (regno));
    unsigned int i;
    EXECUTE_IF_SET_IN_SPARSESET (pseudos_live, i)
-    {
-      if (ignore_reg_for_conflicts != NULL_RTX
-         && REGNO (ignore_reg_for_conflicts) == i)
-       continue;
-      SET_HARD_REG_BIT (lra_reg_info[i].conflict_hard_regs, regno);
-    }
+    SET_HARD_REG_BIT (lra_reg_info[i].conflict_hard_regs, regno);
+
+  if (! TEST_HARD_REG_BIT (hard_regs_live, regno))
+    return;
    CLEAR_HARD_REG_BIT (hard_regs_live, regno);
+  sparseset_set_bit (start_dying, regno);
    if (fixed_regs[regno] || TEST_HARD_REG_BIT (hard_regs_spilled_into, regno))
      {
        bitmap_clear_bit (bb_gen_pseudos, regno);
@@ -267,130 +310,69 @@ make_hard_regno_dead (int regno)
      }
  }
-/* Mark pseudo REGNO as living at program point POINT, update START_LIVING
-   and start a new live range for the pseudo corresponding to REGNO if it
-   is necessary.  */
+/* Mark pseudo REGNO as now being live and update START_LIVING.  */
  static void
-mark_pseudo_live (int regno, int point)
+mark_pseudo_live (int regno)
  {
-  lra_live_range_t p;
+  lra_assert (!HARD_REGISTER_NUM_P (regno));
+  if (sparseset_bit_p (pseudos_live, regno))
+    return;
- lra_assert (regno >= FIRST_PSEUDO_REGISTER);
-  lra_assert (! sparseset_bit_p (pseudos_live, regno));
    sparseset_set_bit (pseudos_live, regno);
-
-  if ((complete_info_p || lra_get_regno_hard_regno (regno) < 0)
-      && ((p = lra_reg_info[regno].live_ranges) == NULL
-         || (p->finish != point && p->finish + 1 != point)))
-     lra_reg_info[regno].live_ranges
-       = create_live_range (regno, point, -1, p);
    sparseset_set_bit (start_living, regno);
  }
-/* Mark pseudo REGNO as not living at program point POINT and update
-   START_DYING.
-   This finishes the current live range for the pseudo corresponding
-   to REGNO.  */
+/* Mark pseudo REGNO as now being dead and update START_DYING.  */
  static void
-mark_pseudo_dead (int regno, int point)
+mark_pseudo_dead (int regno)
  {
-  lra_live_range_t p;
-  int ignore_regno = -1;
-  int end_regno = -1;
+  lra_assert (!HARD_REGISTER_NUM_P (regno));
+  IOR_HARD_REG_SET (lra_reg_info[regno].conflict_hard_regs, hard_regs_live);
+  if (!sparseset_bit_p (pseudos_live, regno))
+    return;
- lra_assert (regno >= FIRST_PSEUDO_REGISTER);
-  lra_assert (sparseset_bit_p (pseudos_live, regno));
    sparseset_clear_bit (pseudos_live, regno);
    sparseset_set_bit (start_dying, regno);
-
-  /* Check whether any part of IGNORE_REG_FOR_CONFLICTS already conflicts
-     with REGNO.  */
-  if (ignore_reg_for_conflicts != NULL_RTX
-      && REGNO (ignore_reg_for_conflicts) < FIRST_PSEUDO_REGISTER)
-    {
-      end_regno = END_REGNO (ignore_reg_for_conflicts);
-      int src_regno = ignore_regno = REGNO (ignore_reg_for_conflicts);
-
-      while (src_regno < end_regno)
-       {
-         if (TEST_HARD_REG_BIT (lra_reg_info[regno].conflict_hard_regs,
-                                src_regno))
-           {
-             ignore_regno = end_regno = -1;
-             break;
-           }
-         src_regno++;
-       }
-    }
-
-  IOR_HARD_REG_SET (lra_reg_info[regno].conflict_hard_regs, hard_regs_live);
-
-  /* If IGNORE_REG_FOR_CONFLICTS did not already conflict with REGNO, make
-     sure it still doesn't.  */
-  for (; ignore_regno < end_regno; ignore_regno++)
-    CLEAR_HARD_REG_BIT (lra_reg_info[regno].conflict_hard_regs, ignore_regno);
-
-  if (complete_info_p || lra_get_regno_hard_regno (regno) < 0)
-    {
-      p = lra_reg_info[regno].live_ranges;
-      lra_assert (p != NULL);
-      p->finish = point;
-    }
  }
-/* Mark register REGNO (pseudo or hard register) in MODE as live at
-   program point POINT.  Update BB_GEN_PSEUDOS.
-   Return TRUE if the liveness tracking sets were modified, or FALSE
-   if nothing changed.  */
-static bool
-mark_regno_live (int regno, machine_mode mode, int point)
+/* Mark register REGNO (pseudo or hard register) in MODE as being live
+   and update BB_GEN_PSEUDOS.  */
+static void
+mark_regno_live (int regno, machine_mode mode)
  {
    int last;
-  bool changed = false;
- if (regno < FIRST_PSEUDO_REGISTER)
+  if (HARD_REGISTER_NUM_P (regno))
      {
        for (last = end_hard_regno (mode, regno); regno < last; regno++)
        make_hard_regno_live (regno);
      }
    else
      {
-      if (! sparseset_bit_p (pseudos_live, regno))
-       {
-         mark_pseudo_live (regno, point);
-         changed = true;
-       }
+      mark_pseudo_live (regno);
        bitmap_set_bit (bb_gen_pseudos, regno);
      }
-  return changed;
  }
-/* Mark register REGNO in MODE as dead at program point POINT. Update
-   BB_GEN_PSEUDOS and BB_KILLED_PSEUDOS.  Return TRUE if the liveness
-   tracking sets were modified, or FALSE if nothing changed.  */
-static bool
-mark_regno_dead (int regno, machine_mode mode, int point)
+/* Mark register REGNO (pseudo or hard register) in MODE as being dead
+   and update BB_GEN_PSEUDOS and BB_KILLED_PSEUDOS.  */
+static void
+mark_regno_dead (int regno, machine_mode mode)
  {
    int last;
-  bool changed = false;
- if (regno < FIRST_PSEUDO_REGISTER)
+  if (HARD_REGISTER_NUM_P (regno))
      {
        for (last = end_hard_regno (mode, regno); regno < last; regno++)
        make_hard_regno_dead (regno);
      }
    else
      {
-      if (sparseset_bit_p (pseudos_live, regno))
-       {
-         mark_pseudo_dead (regno, point);
-         changed = true;
-       }
+      mark_pseudo_dead (regno);
        bitmap_clear_bit (bb_gen_pseudos, regno);
        bitmap_set_bit (bb_killed_pseudos, regno);
      }
-  return changed;
  }
@@ -607,7 +589,7 @@ check_pseudos_live_through_calls (int re
    IOR_HARD_REG_SET (lra_reg_info[regno].conflict_hard_regs,
                    last_call_used_reg_set);
- for (hr = 0; hr < FIRST_PSEUDO_REGISTER; hr++)
+  for (hr = 0; HARD_REGISTER_NUM_P (hr); hr++)
      if (targetm.hard_regno_call_part_clobbered (hr,
                                                PSEUDO_REGNO_MODE (regno)))
        add_to_hard_reg_set (&lra_reg_info[regno].conflict_hard_regs,
@@ -653,7 +635,7 @@ process_bb_lives (basic_block bb, int &c
    rtx link, *link_loc;
    bool need_curr_point_incr;
    HARD_REG_SET last_call_used_reg_set;
-
+
    reg_live_out = df_get_live_out (bb);
    sparseset_clear (pseudos_live);
    sparseset_clear (pseudos_live_through_calls);
@@ -662,7 +644,10 @@ process_bb_lives (basic_block bb, int &c
    REG_SET_TO_HARD_REG_SET (hard_regs_live, reg_live_out);
    AND_COMPL_HARD_REG_SET (hard_regs_live, eliminable_regset);
    EXECUTE_IF_SET_IN_BITMAP (reg_live_out, FIRST_PSEUDO_REGISTER, j, bi)
-    mark_pseudo_live (j, curr_point);
+    {
+      update_pseudo_point (j, curr_point, USE_POINT);
+      mark_pseudo_live (j);
+    }
bb_gen_pseudos = &get_bb_data (bb)->gen_pseudos;
    bb_killed_pseudos = &get_bb_data (bb)->killed_pseudos;
@@ -702,7 +687,7 @@ process_bb_lives (basic_block bb, int &c
        set = single_set (curr_insn);
if (dead_insn_p && set != NULL_RTX
-         && REG_P (SET_DEST (set)) && REGNO (SET_DEST (set)) >= 
FIRST_PSEUDO_REGISTER
+         && REG_P (SET_DEST (set)) && !HARD_REGISTER_P (SET_DEST (set))
          && find_reg_note (curr_insn, REG_EH_REGION, NULL_RTX) == NULL_RTX
          && ! may_trap_p (PATTERN (curr_insn))
          /* Don't do premature remove of pic offset pseudo as we can
@@ -759,7 +744,7 @@ process_bb_lives (basic_block bb, int &c
          if (partial_subreg_p (lra_reg_info[regno].biggest_mode,
                                reg->biggest_mode))
            lra_reg_info[regno].biggest_mode = reg->biggest_mode;
-         if (regno < FIRST_PSEUDO_REGISTER)
+         if (HARD_REGISTER_NUM_P (regno))
            {
              lra_hard_reg_usage[regno] += freq;
              /* A hard register explicitly can be used in small mode,
@@ -775,7 +760,26 @@ process_bb_lives (basic_block bb, int &c
        }
call_p = CALL_P (curr_insn);
-      ignore_reg_for_conflicts = non_conflicting_reg_copy_p (curr_insn);
+
+      /* If we have a simple register copy and the source reg is live after
+        this instruction, then remove the source reg from the live set so
+        that it will not conflict with the destination reg.  */
+      rtx ignore_reg = non_conflicting_reg_copy_p (curr_insn);
+      if (ignore_reg != NULL_RTX)
+       {
+         int ignore_regno = REGNO (ignore_reg);
+         if (HARD_REGISTER_NUM_P (ignore_regno)
+             && TEST_HARD_REG_BIT (hard_regs_live, ignore_regno))
+           CLEAR_HARD_REG_BIT (hard_regs_live, ignore_regno);
+         else if (!HARD_REGISTER_NUM_P (ignore_regno)
+                  && sparseset_bit_p (pseudos_live, ignore_regno))
+           sparseset_clear_bit (pseudos_live, ignore_regno);
+         else
+           /* We don't need any special handling of the source reg if
+              it is dead after this instruction.  */
+           ignore_reg = NULL_RTX;
+       }
+
        src_regno = (set != NULL_RTX && REG_P (SET_SRC (set))
                   ? REGNO (SET_SRC (set)) : -1);
        dst_regno = (set != NULL_RTX && REG_P (SET_DEST (set))
@@ -785,13 +789,13 @@ process_bb_lives (basic_block bb, int &c
          /* Check that source regno does not conflict with
             destination regno to exclude most impossible
             preferences.  */
-         && (((src_regno >= FIRST_PSEUDO_REGISTER
+         && (((!HARD_REGISTER_NUM_P (src_regno)
                && (! sparseset_bit_p (pseudos_live, src_regno)
-                   || (dst_regno >= FIRST_PSEUDO_REGISTER
+                   || (!HARD_REGISTER_NUM_P (dst_regno)
                        && lra_reg_val_equal_p (src_regno,
                                                lra_reg_info[dst_regno].val,
                                                
lra_reg_info[dst_regno].offset))))
-              || (src_regno < FIRST_PSEUDO_REGISTER
+              || (HARD_REGISTER_NUM_P (src_regno)
                   && ! TEST_HARD_REG_BIT (hard_regs_live, src_regno)))
              /* It might be 'inheritance pseudo <- reload pseudo'.  */
              || (src_regno >= lra_constraint_new_regno_start
@@ -816,13 +820,13 @@ process_bb_lives (basic_block bb, int &c
            }
          else if (dst_regno >= lra_constraint_new_regno_start)
            {
-             if ((hard_regno = src_regno) >= FIRST_PSEUDO_REGISTER)
+             if (!HARD_REGISTER_NUM_P (hard_regno = src_regno))
                hard_regno = reg_renumber[src_regno];
              regno = dst_regno;
            }
          else if (src_regno >= lra_constraint_new_regno_start)
            {
-             if ((hard_regno = dst_regno) >= FIRST_PSEUDO_REGISTER)
+             if (!HARD_REGISTER_NUM_P (hard_regno = dst_regno))
                hard_regno = reg_renumber[dst_regno];
              regno = src_regno;
            }
@@ -833,12 +837,6 @@ process_bb_lives (basic_block bb, int &c
sparseset_clear (start_living); - /* Try to avoid unnecessary program point increments, this saves
-        a lot of time in remove_some_program_points_and_update_live_ranges.
-        We only need an increment if something becomes live or dies at this
-        program point.  */
-      need_curr_point_incr = false;
-
        /* Mark each defined value as live.  We need to do this for
         unused values because they still conflict with quantities
         that are live at the time of the definition.  */
@@ -846,14 +844,13 @@ process_bb_lives (basic_block bb, int &c
        {
          if (reg->type != OP_IN)
            {
-             need_curr_point_incr
-               |= mark_regno_live (reg->regno, reg->biggest_mode,
-                                   curr_point);
+             update_pseudo_point (reg->regno, curr_point, USE_POINT);
+             mark_regno_live (reg->regno, reg->biggest_mode);
              check_pseudos_live_through_calls (reg->regno,
                                                last_call_used_reg_set);
            }
- if (reg->regno >= FIRST_PSEUDO_REGISTER)
+         if (!HARD_REGISTER_NUM_P (reg->regno))
            for (hr = curr_static_id->hard_regs; hr != NULL; hr = hr->next)
              if (hr->clobber_high
                  && maybe_gt (GET_MODE_SIZE (PSEUDO_REGNO_MODE (reg->regno)),
@@ -868,7 +865,7 @@ process_bb_lives (basic_block bb, int &c
if (curr_id->arg_hard_regs != NULL)
        for (i = 0; (regno = curr_id->arg_hard_regs[i]) >= 0; i++)
-         if (regno >= FIRST_PSEUDO_REGISTER)
+         if (!HARD_REGISTER_NUM_P (regno))
            /* It is a clobber.  */
            make_hard_regno_live (regno - FIRST_PSEUDO_REGISTER);
@@ -878,20 +875,22 @@ process_bb_lives (basic_block bb, int &c /* See which defined values die here. */
        for (reg = curr_id->regs; reg != NULL; reg = reg->next)
-       if (reg->type == OP_OUT
+       if (reg->type != OP_IN
            && ! reg_early_clobber_p (reg, n_alt) && ! reg->subreg_p)
-         need_curr_point_incr
-           |= mark_regno_dead (reg->regno, reg->biggest_mode,
-                               curr_point);
+         {
+           if (reg->type == OP_OUT)
+             update_pseudo_point (reg->regno, curr_point, DEF_POINT);
+           mark_regno_dead (reg->regno, reg->biggest_mode);
+         }
for (reg = curr_static_id->hard_regs; reg != NULL; reg = reg->next)
-       if (reg->type == OP_OUT
+       if (reg->type != OP_IN
            && ! reg_early_clobber_p (reg, n_alt) && ! reg->subreg_p)
          make_hard_regno_dead (reg->regno);
if (curr_id->arg_hard_regs != NULL)
        for (i = 0; (regno = curr_id->arg_hard_regs[i]) >= 0; i++)
-         if (regno >= FIRST_PSEUDO_REGISTER)
+         if (!HARD_REGISTER_NUM_P (regno))
            /* It is a clobber.  */
            make_hard_regno_dead (regno - FIRST_PSEUDO_REGISTER);
@@ -931,50 +930,63 @@ process_bb_lives (basic_block bb, int &c
        }
/* Increment the current program point if we must. */
-      if (need_curr_point_incr)
+      if (sparseset_contains_pseudos_p (unused_set)
+         || sparseset_contains_pseudos_p (start_dying))
        next_program_point (curr_point, freq);
sparseset_clear (start_living); - need_curr_point_incr = false;
-
        /* Mark each used value as live.        */
        for (reg = curr_id->regs; reg != NULL; reg = reg->next)
-       if (reg->type == OP_IN)
+       if (reg->type != OP_OUT)
          {
-           need_curr_point_incr
-             |= mark_regno_live (reg->regno, reg->biggest_mode,
-                                 curr_point);
+           if (reg->type == OP_IN)
+             update_pseudo_point (reg->regno, curr_point, USE_POINT);
+           mark_regno_live (reg->regno, reg->biggest_mode);
            check_pseudos_live_through_calls (reg->regno,
                                              last_call_used_reg_set);
          }
for (reg = curr_static_id->hard_regs; reg != NULL; reg = reg->next)
-       if (reg->type == OP_IN)
+       if (reg->type != OP_OUT)
          make_hard_regno_live (reg->regno);
if (curr_id->arg_hard_regs != NULL)
        /* Make argument hard registers live.  */
        for (i = 0; (regno = curr_id->arg_hard_regs[i]) >= 0; i++)
-         if (regno < FIRST_PSEUDO_REGISTER)
+         if (HARD_REGISTER_NUM_P (regno))
            make_hard_regno_live (regno);
sparseset_and_compl (dead_set, start_living, start_dying); + /* If we removed the source reg from a simple register copy from the
+        live set, then it will appear to be dead, but it really isn't.  */
+      if (ignore_reg != NULL_RTX)
+       sparseset_clear_bit (dead_set, REGNO (ignore_reg));
+
+      sparseset_clear (start_dying);
+
        /* Mark early clobber outputs dead.  */
        for (reg = curr_id->regs; reg != NULL; reg = reg->next)
-       if (reg->type == OP_OUT
+       if (reg->type != OP_IN
            && reg_early_clobber_p (reg, n_alt) && ! reg->subreg_p)
-         need_curr_point_incr
-           |= mark_regno_dead (reg->regno, reg->biggest_mode,
-                               curr_point);
+         {
+           if (reg->type == OP_OUT)
+             update_pseudo_point (reg->regno, curr_point, DEF_POINT);
+           mark_regno_dead (reg->regno, reg->biggest_mode);
+
+           /* We're done processing inputs, so make sure early clobber
+              operands that are both inputs and outputs are still live.  */
+           if (reg->type == OP_INOUT)
+             mark_regno_live (reg->regno, reg->biggest_mode);
+         }
for (reg = curr_static_id->hard_regs; reg != NULL; reg = reg->next)
-       if (reg->type == OP_OUT
+       if (reg->type != OP_IN
            && reg_early_clobber_p (reg, n_alt) && ! reg->subreg_p)
          {
            struct lra_insn_reg *reg2;
-       
+
            /* We can have early clobbered non-operand hard reg and
               the same hard reg as an insn input.  Don't make hard
               reg dead before the insns.  */
@@ -985,7 +997,9 @@ process_bb_lives (basic_block bb, int &c
              make_hard_regno_dead (reg->regno);
          }
- if (need_curr_point_incr)
+      /* Increment the current program point if we must.  */
+      if (sparseset_contains_pseudos_p (dead_set)
+         || sparseset_contains_pseudos_p (start_dying))
        next_program_point (curr_point, freq);
/* Update notes. */
@@ -1017,7 +1031,6 @@ process_bb_lives (basic_block bb, int &c
        EXECUTE_IF_SET_IN_SPARSESET (unused_set, j)
        add_reg_note (curr_insn, REG_UNUSED, regno_reg_rtx[j]);
      }
-  ignore_reg_for_conflicts = NULL_RTX;
if (bb_has_eh_pred (bb))
      for (j = 0; ; ++j)
@@ -1047,7 +1060,7 @@ process_bb_lives (basic_block bb, int &c
         allocate such regs in this case.  */
        if (!cfun->has_nonlocal_label
          && has_abnormal_call_or_eh_pred_edge_p (bb))
-       for (px = 0; px < FIRST_PSEUDO_REGISTER; px++)
+       for (px = 0; HARD_REGISTER_NUM_P (px); px++)
          if (call_used_regs[px]
  #ifdef REAL_PIC_OFFSET_TABLE_REGNUM
              /* We should create a conflict of PIC pseudo with PIC
@@ -1057,7 +1070,7 @@ process_bb_lives (basic_block bb, int &c
                 pseudo will also have a wrong value.  */
              || (px == REAL_PIC_OFFSET_TABLE_REGNUM
                  && pic_offset_table_rtx != NULL_RTX
-                 && REGNO (pic_offset_table_rtx) >= FIRST_PSEUDO_REGISTER)
+                 && !HARD_REGISTER_P (pic_offset_table_rtx))
  #endif
              )
            make_hard_regno_live (px);
@@ -1095,7 +1108,10 @@ process_bb_lives (basic_block bb, int &c
    need_curr_point_incr = (sparseset_cardinality (pseudos_live) > 0);
EXECUTE_IF_SET_IN_SPARSESET (pseudos_live, i)
-    mark_pseudo_dead (i, curr_point);
+    {
+      update_pseudo_point (i, curr_point, DEF_POINT);
+      mark_pseudo_dead (i);
+    }
EXECUTE_IF_SET_IN_BITMAP (df_get_live_in (bb), FIRST_PSEUDO_REGISTER, j, bi)
      {
@@ -1105,7 +1121,7 @@ process_bb_lives (basic_block bb, int &c
        check_pseudos_live_through_calls (j, last_call_used_reg_set);
      }
- for (i = 0; i < FIRST_PSEUDO_REGISTER; ++i)
+  for (i = 0; HARD_REGISTER_NUM_P (i); ++i)
      {
        if (!TEST_HARD_REG_BIT (hard_regs_live, i))
        continue;
@@ -1332,12 +1348,12 @@ lra_create_live_ranges_1 (bool all_p, bo
         conservative because of recent transformation.  Here in this
         file we recalculate it again as it costs practically
         nothing.  */
-      if (i >= FIRST_PSEUDO_REGISTER && regno_reg_rtx[i] != NULL_RTX)
+      if (!HARD_REGISTER_NUM_P (i) && regno_reg_rtx[i] != NULL_RTX)
        lra_reg_info[i].biggest_mode = GET_MODE (regno_reg_rtx[i]);
        else
        lra_reg_info[i].biggest_mode = VOIDmode;
        lra_reg_info[i].call_p = false;
-      if (i >= FIRST_PSEUDO_REGISTER
+      if (!HARD_REGISTER_NUM_P (i)
          && lra_reg_info[i].nrefs != 0)
        {
          if ((hard_regno = reg_renumber[i]) >= 0)
@@ -1394,7 +1410,7 @@ lra_create_live_ranges_1 (bool all_p, bo
        }
        /* As we did not change CFG since LRA start we can use
         DF-infrastructure solver to solve live data flow problem.  */
-      for (int i = 0; i < FIRST_PSEUDO_REGISTER; ++i)
+      for (int i = 0; HARD_REGISTER_NUM_P (i); ++i)
        {
          if (TEST_HARD_REG_BIT (hard_regs_spilled_into, i))
            bitmap_clear_bit (&all_hard_regs_bitmap, i);

Reply via email to