]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
sched-int.h (bb_note): Move to...
authorRichard Sandiford <rdsandiford@googlemail.com>
Mon, 9 Jan 2012 19:43:10 +0000 (19:43 +0000)
committerRichard Sandiford <rsandifo@gcc.gnu.org>
Mon, 9 Jan 2012 19:43:10 +0000 (19:43 +0000)
gcc/
* sched-int.h (bb_note): Move to...
* basic-block.h: ...here.
* haifa-sched.c (bb_note): Move to...
* cfgrtl.c: ...here.
* function.c (next_block_for_reg): New function.
(move_insn_for_shrink_wrap): Likewise.
(prepare_shrink_wrap): Rewrite to use the above.

From-SVN: r183028

gcc/ChangeLog
gcc/basic-block.h
gcc/cfgrtl.c
gcc/function.c
gcc/haifa-sched.c
gcc/sched-int.h

index 202042abf5a24359faed2ee1650a72d262a777c7..6affd168e7ca2941335423a262c43bbcda0faa72 100644 (file)
@@ -1,3 +1,13 @@
+2012-01-09  Richard Sandiford  <rdsandiford@googlemail.com>
+
+       * sched-int.h (bb_note): Move to...
+       * basic-block.h: ...here.
+       * haifa-sched.c (bb_note): Move to...
+       * cfgrtl.c: ...here.
+       * function.c (next_block_for_reg): New function.
+       (move_insn_for_shrink_wrap): Likewise.
+       (prepare_shrink_wrap): Rewrite to use the above.
+
 2012-01-09  Aldy Hernandez  <aldyh@redhat.com>
 
        * gimple.c (is_gimple_non_addressable): Remove.
index e36b20a38923e98fe78cae0898296fe435d4ba9c..3ff1cd645ea42194ab51e4f6ad7be05cb514a37b 100644 (file)
@@ -801,6 +801,7 @@ extern void flow_edge_list_print (const char *, const edge *, int, FILE *);
 
 /* In cfgrtl.c  */
 extern rtx block_label (basic_block);
+extern rtx bb_note (basic_block);
 extern bool purge_all_dead_edges (void);
 extern bool purge_dead_edges (basic_block);
 extern bool fixup_abnormal_edges (void);
index 635955b799033b058b55761a7ebabd092e4c345e..9312a4b69f1fa7de055c3168a2a02b4be99dd2e7 100644 (file)
@@ -500,6 +500,20 @@ update_bb_for_insn (basic_block bb)
 }
 
 \f
+/* Return the NOTE_INSN_BASIC_BLOCK of BB.  */
+rtx
+bb_note (basic_block bb)
+{
+  rtx note;
+
+  note = BB_HEAD (bb);
+  if (LABEL_P (note))
+    note = NEXT_INSN (note);
+
+  gcc_assert (NOTE_INSN_BASIC_BLOCK_P (note));
+  return note;
+}
+
 /* Return the INSN immediately following the NOTE_INSN_BASIC_BLOCK
    note associated with the BLOCK.  */
 
index 506ec030745bb0fb46016fbac96ebce98c12d647..cd82da404d29e7e8481d2b5b8a8a61a0ba4828fa 100644 (file)
@@ -5329,126 +5329,182 @@ requires_stack_frame_p (rtx insn, HARD_REG_SET prologue_used,
   return false;
 }
 
-/* Look for sets of call-saved registers in the first block of the
-   function, and move them down into successor blocks if the register
-   is used only on one path.  This exposes more opportunities for
-   shrink-wrapping.
-   These kinds of sets often occur when incoming argument registers are
-   moved to call-saved registers because their values are live across
-   one or more calls during the function.  */
+/* See whether BB has a single successor that uses [REGNO, END_REGNO),
+   and if BB is its only predecessor.  Return that block if so,
+   otherwise return null.  */
 
-static void
-prepare_shrink_wrap (basic_block entry_block)
+static basic_block
+next_block_for_reg (basic_block bb, int regno, int end_regno)
 {
-  rtx insn, curr;
-  FOR_BB_INSNS_SAFE (entry_block, insn, curr)
+  edge e, live_edge;
+  edge_iterator ei;
+  bitmap live;
+  int i;
+
+  live_edge = NULL;
+  FOR_EACH_EDGE (e, ei, bb->succs)
     {
-      basic_block next_bb;
-      edge e, live_edge;
-      edge_iterator ei;
-      rtx set, scan;
-      unsigned destreg, srcreg;
+      live = df_get_live_in (e->dest);
+      for (i = regno; i < end_regno; i++)
+       if (REGNO_REG_SET_P (live, i))
+         {
+           if (live_edge && live_edge != e)
+             return NULL;
+           live_edge = e;
+         }
+    }
 
-      if (!NONDEBUG_INSN_P (insn))
-       continue;
-      set = single_set (insn);
-      if (!set)
-       continue;
+  /* We can sometimes encounter dead code.  Don't try to move it
+     into the exit block.  */
+  if (!live_edge || live_edge->dest == EXIT_BLOCK_PTR)
+    return NULL;
 
-      if (!REG_P (SET_SRC (set)) || !REG_P (SET_DEST (set)))
-       continue;
-      srcreg = REGNO (SET_SRC (set));
-      destreg = REGNO (SET_DEST (set));
-      if (hard_regno_nregs[srcreg][GET_MODE (SET_SRC (set))] > 1
-         || hard_regno_nregs[destreg][GET_MODE (SET_DEST (set))] > 1)
-       continue;
+  /* Reject targets of abnormal edges.  This is needed for correctness
+     on ports like Alpha and MIPS, whose pic_offset_table_rtx can die on
+     exception edges even though it is generally treated as call-saved
+     for the majority of the compilation.  Moving across abnormal edges
+     isn't going to be interesting for shrink-wrap usage anyway.  */
+  if (live_edge->flags & EDGE_ABNORMAL)
+    return NULL;
 
-      next_bb = entry_block;
-      scan = insn;
+  if (EDGE_COUNT (live_edge->dest->preds) > 1)
+    return NULL;
 
-      for (;;)
+  return live_edge->dest;
+}
+
+/* Try to move INSN from BB to a successor.  Return true on success.
+   USES and DEFS are the set of registers that are used and defined
+   after INSN in BB.  */
+
+static bool
+move_insn_for_shrink_wrap (basic_block bb, rtx insn,
+                          const HARD_REG_SET uses,
+                          const HARD_REG_SET defs)
+{
+  rtx set, src, dest;
+  bitmap live_out, live_in, bb_uses, bb_defs;
+  unsigned int i, dregno, end_dregno, sregno, end_sregno;
+  basic_block next_block;
+
+  /* Look for a simple register copy.  */
+  set = single_set (insn);
+  if (!set)
+    return false;
+  src = SET_SRC (set);
+  dest = SET_DEST (set);
+  if (!REG_P (dest) || !REG_P (src))
+    return false;
+
+  /* Make sure that the source register isn't defined later in BB.  */
+  sregno = REGNO (src);
+  end_sregno = END_REGNO (src);
+  if (overlaps_hard_reg_set_p (defs, GET_MODE (src), sregno))
+    return false;
+
+  /* Make sure that the destination register isn't referenced later in BB.  */
+  dregno = REGNO (dest);
+  end_dregno = END_REGNO (dest);
+  if (overlaps_hard_reg_set_p (uses, GET_MODE (dest), dregno)
+      || overlaps_hard_reg_set_p (defs, GET_MODE (dest), dregno))
+    return false;
+
+  /* See whether there is a successor block to which we could move INSN.  */
+  next_block = next_block_for_reg (bb, dregno, end_dregno);
+  if (!next_block)
+    return false;
+
+  /* At this point we are committed to moving INSN, but let's try to
+     move it as far as we can.  */
+  do
+    {
+      live_out = df_get_live_out (bb);
+      live_in = df_get_live_in (next_block);
+      bb = next_block;
+
+      /* Check whether BB uses DEST or clobbers DEST.  We need to add
+        INSN to BB if so.  Either way, DEST is no longer live on entry,
+        except for any part that overlaps SRC (next loop).  */
+      bb_uses = &DF_LR_BB_INFO (bb)->use;
+      bb_defs = &DF_LR_BB_INFO (bb)->def;
+      for (i = dregno; i < end_dregno; i++)
        {
-         live_edge = NULL;
-         /* Try to find a single edge across which the register is live.
-            If we find one, we'll try to move the set across this edge.  */
-         FOR_EACH_EDGE (e, ei, next_bb->succs)
-           {
-             if (REGNO_REG_SET_P (df_get_live_in (e->dest), destreg))
-               {
-                 if (live_edge)
-                   {
-                     live_edge = NULL;
-                     break;
-                   }
-                 live_edge = e;
-               }
-           }
-         if (!live_edge)
-           break;
-         /* We can sometimes encounter dead code.  Don't try to move it
-            into the exit block.  */
-         if (live_edge->dest == EXIT_BLOCK_PTR)
-           break;
-         if (EDGE_COUNT (live_edge->dest->preds) > 1)
-           break;
-         while (scan != BB_END (next_bb))
-           {
-             scan = NEXT_INSN (scan);
-             if (NONDEBUG_INSN_P (scan))
-               {
-                 rtx link;
-                 HARD_REG_SET set_regs;
-
-                 CLEAR_HARD_REG_SET (set_regs);
-                 note_stores (PATTERN (scan), record_hard_reg_sets,
-                              &set_regs);
-                 if (CALL_P (scan))
-                   IOR_HARD_REG_SET (set_regs, call_used_reg_set);
-                 for (link = REG_NOTES (scan); link; link = XEXP (link, 1))
-                   if (REG_NOTE_KIND (link) == REG_INC)
-                     record_hard_reg_sets (XEXP (link, 0), NULL, &set_regs);
-
-                 if (TEST_HARD_REG_BIT (set_regs, srcreg)
-                     || reg_referenced_p (SET_DEST (set),
-                                          PATTERN (scan)))
-                   {
-                     scan = NULL_RTX;
-                     break;
-                   }
-                 if (CALL_P (scan))
-                   {
-                     rtx link = CALL_INSN_FUNCTION_USAGE (scan);
-                     while (link)
-                       {
-                         rtx tmp = XEXP (link, 0);
-                         if (GET_CODE (tmp) == USE
-                             && reg_referenced_p (SET_DEST (set), tmp))
-                           break;
-                         link = XEXP (link, 1);
-                       }
-                     if (link)
-                       {
-                         scan = NULL_RTX;
-                         break;
-                       }
-                   }
-               }
-           }
-         if (!scan)
-           break;
-         next_bb = live_edge->dest;
+         if (REGNO_REG_SET_P (bb_uses, i) || REGNO_REG_SET_P (bb_defs, i))
+           next_block = NULL;
+         CLEAR_REGNO_REG_SET (live_out, i);
+         CLEAR_REGNO_REG_SET (live_in, i);
        }
 
-      if (next_bb != entry_block)
+      /* Check whether BB clobbers SRC.  We need to add INSN to BB if so.
+        Either way, SRC is now live on entry.  */
+      for (i = sregno; i < end_sregno; i++)
        {
-         rtx after = BB_HEAD (next_bb);
-         while (!NOTE_P (after)
-                || NOTE_KIND (after) != NOTE_INSN_BASIC_BLOCK)
-           after = NEXT_INSN (after);
-         emit_insn_after (PATTERN (insn), after);
-         delete_insn (insn);
+         if (REGNO_REG_SET_P (bb_defs, i))
+           next_block = NULL;
+         SET_REGNO_REG_SET (live_out, i);
+         SET_REGNO_REG_SET (live_in, i);
        }
+
+      /* If we don't need to add the move to BB, look for a single
+        successor block.  */
+      if (next_block)
+       next_block = next_block_for_reg (next_block, dregno, end_dregno);
     }
+  while (next_block);
+
+  /* BB now defines DEST.  It only uses the parts of DEST that overlap SRC
+     (next loop).  */
+  for (i = dregno; i < end_dregno; i++)
+    {
+      CLEAR_REGNO_REG_SET (bb_uses, i);
+      SET_REGNO_REG_SET (bb_defs, i);
+    }
+
+  /* BB now uses SRC.  */
+  for (i = sregno; i < end_sregno; i++)
+    SET_REGNO_REG_SET (bb_uses, i);
+
+  emit_insn_after (PATTERN (insn), bb_note (bb));
+  delete_insn (insn);
+  return true;
+}
+
+/* Look for register copies in the first block of the function, and move
+   them down into successor blocks if the register is used only on one
+   path.  This exposes more opportunities for shrink-wrapping.  These
+   kinds of sets often occur when incoming argument registers are moved
+   to call-saved registers because their values are live across one or
+   more calls during the function.  */
+
+static void
+prepare_shrink_wrap (basic_block entry_block)
+{
+  rtx insn, curr, x;
+  HARD_REG_SET uses, defs;
+  df_ref *ref;
+
+  CLEAR_HARD_REG_SET (uses);
+  CLEAR_HARD_REG_SET (defs);
+  FOR_BB_INSNS_REVERSE_SAFE (entry_block, insn, curr)
+    if (NONDEBUG_INSN_P (insn)
+       && !move_insn_for_shrink_wrap (entry_block, insn, uses, defs))
+      {
+       /* Add all defined registers to DEFs.  */
+       for (ref = DF_INSN_DEFS (insn); *ref; ref++)
+         {
+           x = DF_REF_REG (*ref);
+           if (REG_P (x) && HARD_REGISTER_P (x))
+             SET_HARD_REG_BIT (defs, REGNO (x));
+         }
+
+       /* Add all used registers to USESs.  */
+       for (ref = DF_INSN_USES (insn); *ref; ref++)
+         {
+           x = DF_REF_REG (*ref);
+           if (REG_P (x) && HARD_REGISTER_P (x))
+             SET_HARD_REG_BIT (uses, REGNO (x));
+         }
+      }
 }
 
 #endif
index 4db23139b10105cd4d51a2416d5aef100b93800f..4e1909a535fa709caf3e88c85fdb88a4ad46d96f 100644 (file)
@@ -6489,20 +6489,6 @@ add_jump_dependencies (rtx insn, rtx jump)
   gcc_assert (!sd_lists_empty_p (jump, SD_LIST_BACK));
 }
 
-/* Return the NOTE_INSN_BASIC_BLOCK of BB.  */
-rtx
-bb_note (basic_block bb)
-{
-  rtx note;
-
-  note = BB_HEAD (bb);
-  if (LABEL_P (note))
-    note = NEXT_INSN (note);
-
-  gcc_assert (NOTE_INSN_BASIC_BLOCK_P (note));
-  return note;
-}
-
 /* Extend data structures for logical insn UID.  */
 void
 sched_extend_luids (void)
index 9b29ea158cb8b3052ed132c79922879f3fbfdcbd..2fa5f759e85ab301b691507e5c744343422e7873 100644 (file)
@@ -130,7 +130,6 @@ extern void sched_insns_init (rtx);
 extern void sched_insns_finish (void);
 
 extern void *xrecalloc (void *, size_t, size_t, size_t);
-extern rtx bb_note (basic_block);
 
 extern void reemit_notes (rtx);