jump.c (duplicate_loop_exit_test): Don't refuse to copy a section of code just becaus...
authorMark Mitchell <mark@markmitchell.com>
Mon, 6 Jul 1998 10:42:43 +0000 (10:42 +0000)
committerMark Mitchell <mmitchel@gcc.gnu.org>
Mon, 6 Jul 1998 10:42:43 +0000 (10:42 +0000)
* jump.c (duplicate_loop_exit_test): Don't refuse to copy a
section of code just because it contains
NOTE_INSN_BLOCK_{BEG,END}.
* stmt.c (expand_end_loop): Likewise.  Also, don't refuse to
move CALL_INSNs or CODE_LABELs.  When moving code, don't move
NOTE_INSN_BLOCK_{BEG,END}.

From-SVN: r20952

gcc/ChangeLog
gcc/jump.c
gcc/stmt.c

index 922b65a977300a460e40369da4d1a29277e7ea65..5898e8053b9ce467872e4d24e713ba9b42592156 100644 (file)
@@ -1,3 +1,12 @@
+Mon Jul  6 10:42:05 1998  Mark Mitchell  <mark@markmitchell.com>
+
+       * jump.c (duplicate_loop_exit_test): Don't refuse to copy a
+       section of code just because it contains
+       NOTE_INSN_BLOCK_{BEG,END}.
+       * stmt.c (expand_end_loop): Likewise.  Also, don't refuse to 
+       move CALL_INSNs or CODE_LABELs.  When moving code, don't move
+       NOTE_INSN_BLOCK_{BEG,END}.
+
 Mon Jul  6 09:38:15 1998  Mark Mitchell  <mark@markmitchell.com>
 
        * cse.c (CSE_ADDRESS_COST): New macro, based on ADDRESS_COST, but 
index 50a69c59fc004f1f5ae76714035b314f2ba061fd..389a6ff1e6441c4c22f178068411d1a70ebe5729 100644 (file)
@@ -2403,10 +2403,18 @@ duplicate_loop_exit_test (loop_start)
             This can be avoided by checking here for NOTE_INSN_LOOP_CONT.  */
 
          if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_BEG
-             || NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_BEG
-             || NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_END
              || NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_CONT)
            return 0;
+
+         if (optimize < 2
+             && (NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_BEG
+                 || NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_END))
+           /* If we were to duplicate this code, we would not move
+              the BLOCK notes, and so debugging the moved code would
+              be difficult.  Thus, we only move the code with -O2 or
+              higher.  */
+           return 0;
+
          break;
        case JUMP_INSN:
        case INSN:
index 43cf7f82ec264e75e5a6dc7d500f721e244da0d5..18ca944ee2d816232212d52397132114e4cdc1e9 100644 (file)
@@ -1923,17 +1923,33 @@ expand_end_loop ()
 
   do_pending_stack_adjust ();
 
-  /* If optimizing, perhaps reorder the loop.  If the loop
-     starts with a conditional exit, roll that to the end
-     where it will optimize together with the jump back.
-
-     We look for the last conditional branch to the exit that we encounter
-     before hitting 30 insns or a CALL_INSN.  If we see an unconditional
-     branch to the exit first, use it.
-
-     We must also stop at NOTE_INSN_BLOCK_BEG and NOTE_INSN_BLOCK_END notes
-     because moving them is not valid.  */
-
+  /* If optimizing, perhaps reorder the loop.  If the loop starts with
+     a loop exit, roll that to the end where it will optimize together
+     with the jump back.
+
+     We look for the conditional branch to the exit, except that once
+     we find such a branch, we don't look past 30 instructions.
+
+     In more detail, if the loop presently looks like this (in pseudo-C):
+
+         start_label:
+         if (test) goto end_label;
+        body;
+        goto start_label;
+        end_label;
+        
+     transform it to look like:
+
+         goto start_label;
+         newstart_label:
+        body;
+        start_label:
+        if (test) goto end_label;
+        goto newstart_label;
+        end_label;
+
+     Here, the `test' may actually consist of some reasonably complex
+     code, terminating in a test.  */
   if (optimize
       &&
       ! (GET_CODE (insn) == JUMP_INSN
@@ -1941,18 +1957,46 @@ expand_end_loop ()
         && SET_DEST (PATTERN (insn)) == pc_rtx
         && GET_CODE (SET_SRC (PATTERN (insn))) == IF_THEN_ELSE))
     {
+      int eh_regions = 0;
+
       /* Scan insns from the top of the loop looking for a qualified
         conditional exit.  */
       for (insn = NEXT_INSN (loop_stack->data.loop.start_label); insn;
           insn = NEXT_INSN (insn))
        {
-         if (GET_CODE (insn) == CALL_INSN || GET_CODE (insn) == CODE_LABEL)
-           break;
+         if (GET_CODE (insn) == NOTE) 
+           {
+             if (optimize < 2
+                 && (NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_BEG
+                     || NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_END))
+               /* The code that actually moves the exit test will
+                  carefully leave BLOCK notes in their original
+                  location.  That means, however, that we can't debug
+                  the exit test itself.  So, we refuse to move code
+                  containing BLOCK notes at low optimization levels.  */
+               break;
+
+             if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_BEG)
+               ++eh_regions;
+             else if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_END)
+               {
+                 --eh_regions;
+                 if (eh_regions < 0) 
+                   /* We've come to the end of an EH region, but
+                      never saw the beginning of that region.  That
+                      means that an EH region begins before the top
+                      of the loop, and ends in the middle of it.  The
+                      existence of such a situation violates a basic
+                      assumption in this code, since that would imply
+                      that even when EH_REGIONS is zero, we might
+                      move code out of an exception region.  */
+                   abort ();
+               }
 
-         if (GET_CODE (insn) == NOTE
-             && (NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_BEG
-                 || NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_END))
-           break;
+             /* We already know this INSN is a NOTE, so there's no
+                point in looking at it to see if it's a JUMP.  */
+             continue;
+           }
 
          if (GET_CODE (insn) == JUMP_INSN || GET_CODE (insn) == INSN)
            num_insns++;
@@ -1960,6 +2004,36 @@ expand_end_loop ()
          if (last_test_insn && num_insns > 30)
            break;
 
+         if (eh_regions > 0) 
+           /* We don't want to move a partial EH region.  Consider:
+
+                 while ( ( { try {
+                               if (cond ()) 0; 
+                               else {
+                                 bar();
+                                 1;
+                               }
+                             } catch (...) { 
+                               1;
+                             } )) {
+                    body;
+                 } 
+
+               This isn't legal C++, but here's what it's supposed to
+               mean: if cond() is true, stop looping.  Otherwise,
+               call bar, and keep looping.  In addition, if cond
+               throws an exception, catch it and keep looping. Such
+               constructs are certainy legal in LISP.  
+
+               We should not move the `if (cond()) 0' test since then
+               the EH-region for the try-block would be broken up.
+               (In this case we would the EH_BEG note for the `try'
+               and `if cond()' but not the call to bar() or the
+               EH_END note.)  
+
+               So we don't look for tests within an EH region.  */
+           continue;
+
          if (GET_CODE (insn) == JUMP_INSN && GET_CODE (PATTERN (insn)) == SET
              && SET_DEST (PATTERN (insn)) == pc_rtx
              && GET_CODE (SET_SRC (PATTERN (insn))) == IF_THEN_ELSE
@@ -1994,6 +2068,7 @@ expand_end_loop ()
             to jump to there.  */
          register rtx newstart_label = gen_label_rtx ();
          register rtx start_move = start_label;
+         rtx next_insn;
 
          /* If the start label is preceded by a NOTE_INSN_LOOP_CONT note,
             then we want to move this note also.  */
@@ -2003,7 +2078,38 @@ expand_end_loop ()
            start_move = PREV_INSN (start_move);
 
          emit_label_after (newstart_label, PREV_INSN (start_move));
-         reorder_insns (start_move, last_test_insn, get_last_insn ());
+
+         /* Actually move the insns.  Start at the beginning, and
+            keep copying insns until we've copied the
+            last_test_insn.  */
+         for (insn = start_move; insn; insn = next_insn)
+           {
+             /* Figure out which insn comes after this one.  We have
+                to do this before we move INSN.  */
+             if (insn == last_test_insn)
+               /* We've moved all the insns.  */
+               next_insn = NULL_RTX;
+             else
+               next_insn = NEXT_INSN (insn);
+
+             if (GET_CODE (insn) == NOTE
+                 && (NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_BEG
+                     || NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_END))
+               /* We don't want to move NOTE_INSN_BLOCK_BEGs or
+                  NOTE_INSN_BLOCK_ENDs because the correct generation
+                  of debugging information depends on these appearing
+                  in the same order in the RTL and in the tree
+                  structure, where they are represented as BLOCKs.
+                  So, we don't move block notes.  Of course, moving
+                  the code inside the block is likely to make it
+                  impossible to debug the instructions in the exit
+                  test, but such is the price of optimization.  */
+               continue;
+
+             /* Move the INSN.  */
+             reorder_insns (insn, insn, get_last_insn ());
+           }
+
          emit_jump_insn_after (gen_jump (start_label),
                                PREV_INSN (newstart_label));
          emit_barrier_after (PREV_INSN (newstart_label));