flow.c (merge_blocks_move_predecessor_nojumps): New function.
authorJeffrey A Law <law@cygnus.com>
Mon, 20 Sep 1999 12:34:26 +0000 (12:34 +0000)
committerJeff Law <law@gcc.gnu.org>
Mon, 20 Sep 1999 12:34:26 +0000 (06:34 -0600)
        * flow.c (merge_blocks_move_predecessor_nojumps): New function.
        (merge-blocks_move_successor_nojumps): Likewise.
        (merge_blocks): Allow merging of some blocks, even if it requires
        physical movement of the blocks, but not if it requires new jumps.

From-SVN: r29519

gcc/ChangeLog
gcc/flow.c

index 72dcdf613038a9333f8eeb2829c87485a33f90f9..9d070d179461f362ea8bb2c83829195327dd691c 100644 (file)
@@ -1,5 +1,10 @@
 Mon Sep 20 05:41:36 1999  Jeffrey A Law  (law@cygnus.com)
 
+       * flow.c (merge_blocks_move_predecessor_nojumps): New function.
+       (merge-blocks_move_successor_nojumps): Likewise.
+       (merge_blocks): Allow merging of some blocks, even if it requires
+       physical movement of the blocks, but not if it requires new jumps.
+
        * bitmap.c (debug_bitmap_file): Renmaed from bitmap_debug_file.
        Callers and prototype changed.
        * bitmap.h: Fix debug_bitmap and debug_bitmap_file prototypes.
index c7f2d15f58f72fc875452a7d47a5d9f227e1ffdf..834af4db00f0c2f93fb6adb6b84455131ca9630c 100644 (file)
@@ -1847,6 +1847,95 @@ can_delete_label_p (label)
   return 1;
 }
 
+/* Blocks A and B are to be merged into a single block.  A has no incoming
+   fallthru edge, so it can be moved before B without adding or modifying
+   any jumps (aside from the jump from A to B).  */
+
+static int
+merge_blocks_move_predecessor_nojumps (e, a, b)
+     edge e;
+     basic_block a, b;
+{
+  rtx start, end, insertpoint, barrier;
+
+  start = a->head;
+  end = a->end;
+  insertpoint = PREV_INSN (b->head);
+
+  /* We want to delete the BARRIER after the end of the insns we are
+     going to move.  If we don't find a BARRIER, then do nothing.  This
+     can happen in some cases if we have labels we can not delete. 
+
+     Similarly, do nothing if we can not delete the label at the start
+     of the target block.  */
+  barrier = next_nonnote_insn (end);
+  if (GET_CODE (barrier) != BARRIER
+      || (GET_CODE (b->head) == CODE_LABEL
+         && ! can_delete_label_p (b->head)))
+    return 0;
+  else
+    flow_delete_insn (barrier);
+
+  /* Move block and loop notes out of the chain so that we do not
+     disturb their order.
+
+     ??? A better solution would be to squeeze out all the non-nested notes
+     and adjust the block trees appropriately.   Even better would be to have
+     a tighter connection between block trees and rtl so that this is not
+     necessary.  */
+  start = squeeze_notes (start, end);
+
+  /* Scramble the insn chain.  */
+  reorder_insns (start, end, insertpoint);
+
+  /* Now blocks A and B are contiguous.  Merge them.  */
+  merge_blocks_nomove (a, b);
+  return 1;
+}
+
+/* Blocks A and B are to be merged into a single block.  B has no outgoing
+   fallthru edge, so it can be moved after A without adding or modifying
+   any jumps (aside from the jump from A to B).  */
+
+static int
+merge_blocks_move_successor_nojumps (e, a, b)
+     edge e;
+     basic_block a, b;
+{
+  rtx start, end, insertpoint, barrier;
+
+  start = b->head;
+  end = b->end;
+  insertpoint = a->end;
+
+  /* We want to delete the BARRIER before the start of the insns we are
+     going to move.  If we don't find a BARRIER, then do nothing.  This
+     can happen in some cases if we have labels we can not delete.  */
+  barrier = prev_nonnote_insn (start);
+  if (GET_CODE (barrier) != BARRIER
+      || (GET_CODE (b->head) == CODE_LABEL
+         && ! can_delete_label_p (b->head)))
+    return 0;
+  else
+    flow_delete_insn (barrier);
+
+  /* Move block and loop notes out of the chain so that we do not
+     disturb their order.
+
+     ??? A better solution would be to squeeze out all the non-nested notes
+     and adjust the block trees appropriately.   Even better would be to have
+     a tighter connection between block trees and rtl so that this is not
+     necessary.  */
+  start = squeeze_notes (start, end);
+
+  /* Scramble the insn chain.  */
+  reorder_insns (start, end, insertpoint);
+
+  /* Now blocks A and B are contiguous.  Merge them.  */
+  merge_blocks_nomove (a, b);
+  return 1;
+}
+
 /* Blocks A and B are to be merged into a single block.  The insns
    are already contiguous, hence `nomove'.  */
 
@@ -1946,19 +2035,58 @@ merge_blocks (e, b, c)
   /* If B has a fallthru edge to C, no need to move anything.  */
   if (!(e->flags & EDGE_FALLTHRU))
     {
+      edge tmp_edge;
+      int c_has_outgoing_fallthru;
+      int b_has_incoming_fallthru;
+
       /* ??? From here on out we must make sure to not munge nesting
-        of exception regions and lexical blocks.  Need to think about
-        these cases before this gets implemented.  */
-      return 0;
+        of exception regions and lexical blocks.
+
+        A few notes on the subject:
+
+         Not only do we have to be careful not to lose the nesting of
+         exception regions or lexical blocks, we also have to be careful
+         about merging blocks which are in different EH regions.
+
+         A call that throws may end a block.  The insn to copy the return
+         value from its hard reg into a pseudo could end up in a
+         different block than the call.  Moving either block might cause
+         problems for SMALL_REGISTER_CLASS machines.
 
-      /* If C has an outgoing fallthru, and B does not have an incoming
-        fallthru, move B before C.  The later clause is somewhat arbitrary,
-        but avoids modifying blocks other than the two we've been given.  */
+         A throw/catch edge (or any abnormal edge) should be rarely
+         executed and we may want to treat blocks which have two out
+         edges, one normal, one abnormal as only having one edge for
+         block merging purposes.
 
-      /* Otherwise, move C after B.  If C had a fallthru, which doesn't
-        happen to be the physical successor to B, insert an unconditional
-        branch.  If C already ended with a conditional branch, the new
-        jump must go in a new basic block D.  */
+         For now we avoid the EH issues by not allowing any physical
+         block movement when exception handling is enabled.  */
+      if (flag_exceptions)
+       return 0;
+
+      for (tmp_edge = c->succ; tmp_edge ; tmp_edge = tmp_edge->succ_next)
+       if (tmp_edge->flags & EDGE_FALLTHRU)
+         break;
+      c_has_outgoing_fallthru = (tmp_edge != NULL);
+
+      for (tmp_edge = b->pred; tmp_edge ; tmp_edge = tmp_edge->pred_next)
+       if (tmp_edge->flags & EDGE_FALLTHRU)
+         break;
+      b_has_incoming_fallthru = (tmp_edge != NULL);
+
+      /* If B does not have an incoming fallthru, then it can be moved
+        immediately before C without introducing or modifying jumps.
+
+        Else if C does not have an outgoing fallthru, then it can be moved
+        immediately after B without introducing or modifying jumps.
+
+        Else move C after B, which will likely require insertion of a
+        new jump.  ??? Not implemented yet.  */
+      if (! b_has_incoming_fallthru)
+       return merge_blocks_move_predecessor_nojumps (e, b, c);
+      else if (! c_has_outgoing_fallthru)
+       return merge_blocks_move_successor_nojumps (e, b, c);
+      else
+       return 0;
     }
 
   /* If a label still appears somewhere and we cannot delete the label,