]> git.ipfire.org Git - thirdparty/gcc.git/blobdiff - gcc/lra-lives.c
Correct a function pre/postcondition [PR102403].
[thirdparty/gcc.git] / gcc / lra-lives.c
index 55b2adc2a5beca5953ffbc276041440e563337aa..29531843c633654583a21d06b8b9f9c707a7edf0 100644 (file)
@@ -1,5 +1,5 @@
 /* Build live ranges for pseudos.
-   Copyright (C) 2010-2019 Free Software Foundation, Inc.
+   Copyright (C) 2010-2021 Free Software Foundation, Inc.
    Contributed by Vladimir Makarov <vmakarov@redhat.com>.
 
 This file is part of GCC.
@@ -43,6 +43,7 @@ along with GCC; see the file COPYING3.        If not see
 #include "sparseset.h"
 #include "lra-int.h"
 #include "target.h"
+#include "function-abi.h"
 
 /* Program points are enumerated by numbers from range
    0..LRA_LIVE_MAX_POINT-1.  There are approximately two times more
@@ -280,7 +281,8 @@ static void
 make_hard_regno_live (int regno)
 {
   lra_assert (HARD_REGISTER_NUM_P (regno));
-  if (TEST_HARD_REG_BIT (hard_regs_live, regno))
+  if (TEST_HARD_REG_BIT (hard_regs_live, regno)
+      || TEST_HARD_REG_BIT (eliminable_regset, regno))
     return;
   SET_HARD_REG_BIT (hard_regs_live, regno);
   sparseset_set_bit (start_living, regno);
@@ -294,6 +296,9 @@ make_hard_regno_live (int regno)
 static void
 make_hard_regno_dead (int regno)
 {
+  if (TEST_HARD_REG_BIT (eliminable_regset, regno))
+    return;
+
   lra_assert (HARD_REGISTER_NUM_P (regno));
   unsigned int i;
   EXECUTE_IF_SET_IN_SPARSESET (pseudos_live, i)
@@ -327,7 +332,7 @@ static void
 mark_pseudo_dead (int regno)
 {
   lra_assert (!HARD_REGISTER_NUM_P (regno));
-  IOR_HARD_REG_SET (lra_reg_info[regno].conflict_hard_regs, hard_regs_live);
+  lra_reg_info[regno].conflict_hard_regs |= hard_regs_live;
   if (!sparseset_bit_p (pseudos_live, regno))
     return;
 
@@ -384,8 +389,9 @@ mark_regno_dead (int regno, machine_mode mode)
 
 /* Structure describing local BB data used for pseudo
    live-analysis.  */
-struct bb_data_pseudos
+class bb_data_pseudos
 {
+public:
   /* Basic block about which the below data are.  */
   basic_block bb;
   bitmap_head killed_pseudos; /* pseudos killed in the BB.  */
@@ -393,7 +399,7 @@ struct bb_data_pseudos
 };
 
 /* Array for all BB data.  Indexed by the corresponding BB index.  */
-typedef struct bb_data_pseudos *bb_data_t;
+typedef class bb_data_pseudos *bb_data_t;
 
 /* All basic block data are referred through the following array.  */
 static bb_data_t bb_data;
@@ -469,7 +475,7 @@ initiate_live_solver (void)
 {
   bitmap_initialize (&all_hard_regs_bitmap, &reg_obstack);
   bitmap_set_range (&all_hard_regs_bitmap, 0, FIRST_PSEUDO_REGISTER);
-  bb_data = XNEWVEC (struct bb_data_pseudos, last_basic_block_for_fn (cfun));
+  bb_data = XNEWVEC (class bb_data_pseudos, last_basic_block_for_fn (cfun));
   bitmap_initialize (&all_blocks, &reg_obstack);
 
   basic_block bb;
@@ -574,41 +580,21 @@ lra_setup_reload_pseudo_preferenced_hard_reg (int regno,
     }
 }
 
-/* Check that REGNO living through calls and setjumps, set up conflict
-   regs using LAST_CALL_USED_REG_SET, and clear corresponding bits in
-   PSEUDOS_LIVE_THROUGH_CALLS and PSEUDOS_LIVE_THROUGH_SETJUMPS.
-   CALL_INSN is a call that is representative of all calls in the region
-   described by the PSEUDOS_LIVE_THROUGH_* sets, in terms of the registers
-   that it preserves and clobbers.  */
+/* Check whether REGNO lives through calls and setjmps and clear
+   the corresponding bits in PSEUDOS_LIVE_THROUGH_CALLS and
+   PSEUDOS_LIVE_THROUGH_SETJUMPS.  All calls in the region described
+   by PSEUDOS_LIVE_THROUGH_CALLS have the given ABI.  */
 
 static inline void
-check_pseudos_live_through_calls (int regno,
-                                 HARD_REG_SET last_call_used_reg_set,
-                                 rtx_insn *call_insn)
+check_pseudos_live_through_calls (int regno, const function_abi &abi)
 {
-  int hr;
-  rtx_insn *old_call_insn;
-
   if (! sparseset_bit_p (pseudos_live_through_calls, regno))
     return;
 
-  gcc_assert (call_insn && CALL_P (call_insn));
-  old_call_insn = lra_reg_info[regno].call_insn;
-  if (!old_call_insn
-      || (targetm.return_call_with_max_clobbers
-         && targetm.return_call_with_max_clobbers (old_call_insn, call_insn)
-            == call_insn))
-    lra_reg_info[regno].call_insn = call_insn;
+  machine_mode mode = PSEUDO_REGNO_MODE (regno);
 
   sparseset_clear_bit (pseudos_live_through_calls, regno);
-  IOR_HARD_REG_SET (lra_reg_info[regno].conflict_hard_regs,
-                   last_call_used_reg_set);
-
-  for (hr = 0; HARD_REGISTER_NUM_P (hr); hr++)
-    if (targetm.hard_regno_call_part_clobbered (call_insn, hr,
-                                               PSEUDO_REGNO_MODE (regno)))
-      add_to_hard_reg_set (&lra_reg_info[regno].conflict_hard_regs,
-                          PSEUDO_REGNO_MODE (regno), hr);
+  lra_reg_info[regno].conflict_hard_regs |= abi.mode_clobbers (mode);
   if (! sparseset_bit_p (pseudos_live_through_setjumps, regno))
     return;
   sparseset_clear_bit (pseudos_live_through_setjumps, regno);
@@ -623,23 +609,36 @@ check_pseudos_live_through_calls (int regno,
 static inline bool
 reg_early_clobber_p (const struct lra_insn_reg *reg, int n_alt)
 {
-  return (reg->early_clobber
-         && (n_alt == LRA_UNKNOWN_ALT
-             || (n_alt != LRA_NON_CLOBBERED_ALT
-                 && TEST_BIT (reg->early_clobber_alts, n_alt))));
+  return (n_alt == LRA_UNKNOWN_ALT
+         ? reg->early_clobber_alts != 0
+         : (n_alt != LRA_NON_CLOBBERED_ALT
+            && TEST_BIT (reg->early_clobber_alts, n_alt)));
 }
 
-/* Return true if call instructions CALL1 and CALL2 use ABIs that
-   preserve the same set of registers.  */
+/* Clear pseudo REGNO in SET or all hard registers of REGNO in MODE in SET.  */
+static void
+clear_sparseset_regnos (sparseset set, int regno, enum machine_mode mode)
+{
+  if (regno >= FIRST_PSEUDO_REGISTER)
+    {
+      sparseset_clear_bit (dead_set, regno);
+      return;
+    }
+  for (int last = end_hard_regno (mode, regno); regno < last; regno++)
+    sparseset_clear_bit (set, regno);
+}
 
+/* Return true if pseudo REGNO is in SET or all hard registers of REGNO in MODE
+   are in SET.  */
 static bool
-calls_have_same_clobbers_p (rtx_insn *call1, rtx_insn *call2)
+regnos_in_sparseset_p (sparseset set, int regno, enum machine_mode mode)
 {
-  if (!targetm.return_call_with_max_clobbers)
-    return false;
-
-  return (targetm.return_call_with_max_clobbers (call1, call2) == call1
-          && targetm.return_call_with_max_clobbers (call2, call1) == call2);
+  if (regno >= FIRST_PSEUDO_REGISTER)
+    return sparseset_bit_p (dead_set, regno);
+  for (int last = end_hard_regno (mode, regno); regno < last; regno++)
+    if (!sparseset_bit_p (set, regno))
+      return false;
+  return true;
 }
 
 /* Process insns of the basic block BB to update pseudo live ranges,
@@ -661,17 +660,15 @@ process_bb_lives (basic_block bb, int &curr_point, bool dead_insn_p)
   rtx_insn *next;
   rtx link, *link_loc;
   bool need_curr_point_incr;
-  HARD_REG_SET last_call_used_reg_set;
-  rtx_insn *call_insn = NULL;
-  rtx_insn *last_call_insn = NULL;
+  /* Only has a meaningful value once we've seen a call.  */
+  function_abi last_call_abi = default_function_abi;
 
   reg_live_out = df_get_live_out (bb);
   sparseset_clear (pseudos_live);
   sparseset_clear (pseudos_live_through_calls);
   sparseset_clear (pseudos_live_through_setjumps);
-  CLEAR_HARD_REG_SET (last_call_used_reg_set);
   REG_SET_TO_HARD_REG_SET (hard_regs_live, reg_live_out);
-  AND_COMPL_HARD_REG_SET (hard_regs_live, eliminable_regset);
+  hard_regs_live &= ~eliminable_regset;
   EXECUTE_IF_SET_IN_BITMAP (reg_live_out, FIRST_PSEUDO_REGISTER, j, bi)
     {
       update_pseudo_point (j, curr_point, USE_POINT);
@@ -701,7 +698,7 @@ process_bb_lives (basic_block bb, int &curr_point, bool dead_insn_p)
       bool call_p;
       int n_alt, dst_regno, src_regno;
       rtx set;
-      struct lra_insn_reg *reg, *hr;
+      struct lra_insn_reg *reg;
 
       if (!NONDEBUG_INSN_P (curr_insn))
        continue;
@@ -733,7 +730,7 @@ process_bb_lives (basic_block bb, int &curr_point, bool dead_insn_p)
                break;
              }
          for (reg = curr_static_id->hard_regs; reg != NULL; reg = reg->next)
-           if (reg->type != OP_IN && !reg->clobber_high)
+           if (reg->type != OP_IN)
              {
                remove_p = false;
                break;
@@ -768,24 +765,13 @@ process_bb_lives (basic_block bb, int &curr_point, bool dead_insn_p)
       /* Update max ref width and hard reg usage.  */
       for (reg = curr_id->regs; reg != NULL; reg = reg->next)
        {
-         int i, regno = reg->regno;
+         int regno = reg->regno;
 
          if (partial_subreg_p (lra_reg_info[regno].biggest_mode,
                                reg->biggest_mode))
            lra_reg_info[regno].biggest_mode = reg->biggest_mode;
          if (HARD_REGISTER_NUM_P (regno))
-           {
-             lra_hard_reg_usage[regno] += freq;
-             /* A hard register explicitly can be used in small mode,
-                but implicitly it can be used in natural mode as a
-                part of multi-register group.  Process this case
-                here.  */
-             for (i = 1; i < hard_regno_nregs (regno, reg->biggest_mode); i++)
-               if (partial_subreg_p (lra_reg_info[regno + i].biggest_mode,
-                                     GET_MODE (regno_reg_rtx[regno + i])))
-                 lra_reg_info[regno + i].biggest_mode
-                   = GET_MODE (regno_reg_rtx[regno + i]);
-           }
+           lra_hard_reg_usage[regno] += freq;
        }
 
       call_p = CALL_P (curr_insn);
@@ -870,24 +856,13 @@ process_bb_lives (basic_block bb, int &curr_point, bool dead_insn_p)
         unused values because they still conflict with quantities
         that are live at the time of the definition.  */
       for (reg = curr_id->regs; reg != NULL; reg = reg->next)
-       {
-         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,
-                                               call_insn);
-           }
-
-         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)),
-                              GET_MODE_SIZE (hr->biggest_mode)))
-               SET_HARD_REG_BIT (lra_reg_info[reg->regno].conflict_hard_regs,
-                                 hr->regno);
-       }
+       if (reg->type != OP_IN)
+         {
+           update_pseudo_point (reg->regno, curr_point, USE_POINT);
+           mark_regno_live (reg->regno, reg->biggest_mode);
+           /* ??? Should be a no-op for unused registers.  */
+           check_pseudos_live_through_calls (reg->regno, last_call_abi);
+         }
 
       for (reg = curr_static_id->hard_regs; reg != NULL; reg = reg->next)
        if (reg->type != OP_IN)
@@ -926,35 +901,13 @@ process_bb_lives (basic_block bb, int &curr_point, bool dead_insn_p)
 
       if (call_p)
        {
-         call_insn = curr_insn;
-         if (! flag_ipa_ra && ! targetm.return_call_with_max_clobbers)
-           COPY_HARD_REG_SET(last_call_used_reg_set, call_used_reg_set);
-         else
-           {
-             HARD_REG_SET this_call_used_reg_set;
-             get_call_reg_set_usage (curr_insn, &this_call_used_reg_set,
-                                     call_used_reg_set);
-
-             bool flush = (! hard_reg_set_empty_p (last_call_used_reg_set)
-                           && ( ! hard_reg_set_equal_p (last_call_used_reg_set,
-                                                      this_call_used_reg_set)))
-                          || (last_call_insn && ! calls_have_same_clobbers_p
-                                                    (call_insn,
-                                                     last_call_insn));
-
-             EXECUTE_IF_SET_IN_SPARSESET (pseudos_live, j)
-               {
-                 IOR_HARD_REG_SET (lra_reg_info[j].actual_call_used_reg_set,
-                                   this_call_used_reg_set);
+         function_abi call_abi = insn_callee_abi (curr_insn);
 
-                 if (flush)
-                   check_pseudos_live_through_calls (j,
-                                                     last_call_used_reg_set,
-                                                     last_call_insn);
-               }
-             COPY_HARD_REG_SET(last_call_used_reg_set, this_call_used_reg_set);
-             last_call_insn = call_insn;
-           }
+         if (last_call_abi != call_abi)
+           EXECUTE_IF_SET_IN_SPARSESET (pseudos_live, j)
+             check_pseudos_live_through_calls (j, last_call_abi);
+
+         last_call_abi = call_abi;
 
          sparseset_ior (pseudos_live_through_calls,
                         pseudos_live_through_calls, pseudos_live);
@@ -992,9 +945,7 @@ process_bb_lives (basic_block bb, int &curr_point, bool dead_insn_p)
            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,
-                                             call_insn);
+           check_pseudos_live_through_calls (reg->regno, last_call_abi);
          }
 
       for (reg = curr_static_id->hard_regs; reg != NULL; reg = reg->next)
@@ -1055,19 +1006,25 @@ process_bb_lives (basic_block bb, int &curr_point, bool dead_insn_p)
            ;
          else if (REG_P (XEXP (link, 0)))
            {
-             regno = REGNO (XEXP (link, 0));
+             rtx note_reg = XEXP (link, 0);
+             int note_regno = REGNO (note_reg);
+
              if ((REG_NOTE_KIND (link) == REG_DEAD
-                  && ! sparseset_bit_p (dead_set, regno))
+                  && ! regnos_in_sparseset_p (dead_set, note_regno,
+                                              GET_MODE (note_reg)))
                  || (REG_NOTE_KIND (link) == REG_UNUSED
-                     && ! sparseset_bit_p (unused_set, regno)))
+                     && ! regnos_in_sparseset_p (unused_set, note_regno,
+                                                 GET_MODE (note_reg))))
                {
                  *link_loc = XEXP (link, 1);
                  continue;
                }
              if (REG_NOTE_KIND (link) == REG_DEAD)
-               sparseset_clear_bit (dead_set, regno);
+               clear_sparseset_regnos (dead_set, note_regno,
+                                       GET_MODE (note_reg));
              else if (REG_NOTE_KIND (link) == REG_UNUSED)
-               sparseset_clear_bit (unused_set, regno);
+               clear_sparseset_regnos (unused_set, note_regno,
+                                       GET_MODE (note_reg));
            }
          link_loc = &XEXP (link, 1);
        }
@@ -1078,27 +1035,36 @@ process_bb_lives (basic_block bb, int &curr_point, bool dead_insn_p)
     }
 
   if (bb_has_eh_pred (bb))
+    /* Any pseudos that are currently live conflict with the eh_return
+       data registers.  For liveness purposes, these registers are set
+       by artificial definitions at the start of the BB, so are not
+       actually live on entry.  */
     for (j = 0; ; ++j)
       {
        unsigned int regno = EH_RETURN_DATA_REGNO (j);
 
        if (regno == INVALID_REGNUM)
          break;
+
        make_hard_regno_live (regno);
+       make_hard_regno_dead (regno);
       }
 
   /* Pseudos can't go in stack regs at the start of a basic block that
-     is reached by an abnormal edge. Likewise for call clobbered regs,
-     because caller-save, fixup_abnormal_edges and possibly the table
-     driven EH machinery are not quite ready to handle such pseudos
-     live across such edges.  */
+     is reached by an abnormal edge.  Likewise for registers that are at
+     least partly call clobbered, because caller-save, fixup_abnormal_edges
+     and possibly the table driven EH machinery are not quite ready to
+     handle such pseudos live across such edges.  */
   if (bb_has_abnormal_pred (bb))
     {
+      HARD_REG_SET clobbers;
+
+      CLEAR_HARD_REG_SET (clobbers);
 #ifdef STACK_REGS
       EXECUTE_IF_SET_IN_SPARSESET (pseudos_live, px)
        lra_reg_info[px].no_stack_p = true;
       for (px = FIRST_STACK_REG; px <= LAST_STACK_REG; px++)
-       make_hard_regno_live (px);
+       SET_HARD_REG_BIT (clobbers, px);
 #endif
       /* No need to record conflicts for call clobbered regs if we
         have nonlocal labels around, as we don't ever try to
@@ -1106,7 +1072,7 @@ process_bb_lives (basic_block bb, int &curr_point, bool dead_insn_p)
       if (!cfun->has_nonlocal_label
          && has_abnormal_call_or_eh_pred_edge_p (bb))
        for (px = 0; HARD_REGISTER_NUM_P (px); px++)
-         if (call_used_regs[px]
+         if (eh_edge_abi.clobbers_at_least_part_of_reg_p (px)
 #ifdef REAL_PIC_OFFSET_TABLE_REGNUM
              /* We should create a conflict of PIC pseudo with PIC
                 hard reg as PIC hard reg can have a wrong value after
@@ -1118,7 +1084,15 @@ process_bb_lives (basic_block bb, int &curr_point, bool dead_insn_p)
                  && !HARD_REGISTER_P (pic_offset_table_rtx))
 #endif
              )
+           SET_HARD_REG_BIT (clobbers, px);
+
+      clobbers &= ~hard_regs_live;
+      for (px = 0; HARD_REGISTER_NUM_P (px); px++)
+       if (TEST_HARD_REG_BIT (clobbers, px))
+         {
            make_hard_regno_live (px);
+           make_hard_regno_dead (px);
+         }
     }
 
   bool live_change_p = false;
@@ -1163,7 +1137,7 @@ process_bb_lives (basic_block bb, int &curr_point, bool dead_insn_p)
       if (sparseset_cardinality (pseudos_live_through_calls) == 0)
        break;
       if (sparseset_bit_p (pseudos_live_through_calls, j))
-       check_pseudos_live_through_calls (j, last_call_used_reg_set, call_insn);
+       check_pseudos_live_through_calls (j, last_call_abi);
     }
 
   for (i = 0; HARD_REGISTER_NUM_P (i); ++i)
@@ -1397,7 +1371,6 @@ lra_create_live_ranges_1 (bool all_p, bool dead_insn_p)
        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_insn = NULL;
       if (!HARD_REGISTER_NUM_P (i)
          && lra_reg_info[i].nrefs != 0)
        {