OSDN Git Service

(jump_optimize): Fix second error in last change.
[pf3gnuchains/gcc-fork.git] / gcc / jump.c
index 2b9218a..27a382a 100644 (file)
@@ -1,5 +1,5 @@
 /* Optimize jump instructions, for GNU compiler.
 /* Optimize jump instructions, for GNU compiler.
-   Copyright (C) 1987, 88, 89, 91-95, 1996 Free Software Foundation, Inc.b
+   Copyright (C) 1987, 88, 89, 91-95, 1996 Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
 
 This file is part of GNU CC.
 
@@ -60,6 +60,7 @@ Boston, MA 02111-1307, USA.  */
 #include "insn-flags.h"
 #include "expr.h"
 #include "real.h"
 #include "insn-flags.h"
 #include "expr.h"
 #include "real.h"
+#include "except.h"
 
 /* ??? Eventually must record somehow the labels used by jumps
    from nested functions.  */
 
 /* ??? Eventually must record somehow the labels used by jumps
    from nested functions.  */
@@ -100,7 +101,7 @@ int can_reach_end;
    Normally they are not significant, because of A and B jump to C,
    and R dies in A, it must die in B.  But this might not be true after
    stack register conversion, and we must compare death notes in that
    Normally they are not significant, because of A and B jump to C,
    and R dies in A, it must die in B.  But this might not be true after
    stack register conversion, and we must compare death notes in that
-   case. */
+   case.  */
 
 static int cross_jump_death_matters = 0;
 
 
 static int cross_jump_death_matters = 0;
 
@@ -234,6 +235,16 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan)
   for (insn = forced_labels; insn; insn = XEXP (insn, 1))
     LABEL_NUSES (XEXP (insn, 0))++;
 
   for (insn = forced_labels; insn; insn = XEXP (insn, 1))
     LABEL_NUSES (XEXP (insn, 0))++;
 
+  check_exception_handler_labels ();
+
+  /* Keep track of labels used for marking handlers for exception
+     regions; they cannot usually be deleted.  */
+
+  for (insn = exception_handler_labels; insn; insn = XEXP (insn, 1))
+    LABEL_NUSES (XEXP (insn, 0))++;
+
+  exception_optimize ();
+
   /* Delete all labels already not referenced.
      Also find the last insn.  */
 
   /* Delete all labels already not referenced.
      Also find the last insn.  */
 
@@ -438,28 +449,39 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan)
                                              sreg, NULL_PTR, dreg,
                                              GET_MODE (SET_SRC (body)));
 
                                              sreg, NULL_PTR, dreg,
                                              GET_MODE (SET_SRC (body)));
 
-#ifdef PRESERVE_DEATH_INFO_REGNO_P
-                   /* Deleting insn could lose a death-note for SREG or DREG
-                      so don't do it if final needs accurate death-notes.  */
-                   if (! PRESERVE_DEATH_INFO_REGNO_P (sreg)
-                       && ! PRESERVE_DEATH_INFO_REGNO_P (dreg))
-#endif
+                   if (tem != 0 &&
+                       GET_MODE (tem) == GET_MODE (SET_DEST (body)))
                      {
                        /* DREG may have been the target of a REG_DEAD note in
                           the insn which makes INSN redundant.  If so, reorg
                           would still think it is dead.  So search for such a
                           note and delete it if we find it.  */
                      {
                        /* DREG may have been the target of a REG_DEAD note in
                           the insn which makes INSN redundant.  If so, reorg
                           would still think it is dead.  So search for such a
                           note and delete it if we find it.  */
-                       for (trial = prev_nonnote_insn (insn);
-                            trial && GET_CODE (trial) != CODE_LABEL;
-                            trial = prev_nonnote_insn (trial))
-                         if (find_regno_note (trial, REG_DEAD, dreg))
-                           {
-                             remove_death (dreg, trial);
-                             break;
-                           }
-
-                       if (tem != 0
-                           && GET_MODE (tem) == GET_MODE (SET_DEST (body)))
+                       if (! find_regno_note (insn, REG_UNUSED, dreg))
+                         for (trial = prev_nonnote_insn (insn);
+                              trial && GET_CODE (trial) != CODE_LABEL;
+                              trial = prev_nonnote_insn (trial))
+                           if (find_regno_note (trial, REG_DEAD, dreg))
+                             {
+                               remove_death (dreg, trial);
+                               break;
+                             }
+#ifdef PRESERVE_DEATH_INFO_REGNO_P
+                       /* Deleting insn could lose a death-note for SREG
+                          so don't do it if final needs accurate
+                          death-notes.  */
+                       if (PRESERVE_DEATH_INFO_REGNO_P (sreg)
+                           && (trial = find_regno_note (insn, REG_DEAD, sreg)))
+                         {
+                           /* Change this into a USE so that we won't emit
+                              code for it, but still can keep the note.  */
+                           PATTERN (insn)
+                             = gen_rtx (USE, VOIDmode, XEXP (trial, 0));
+                           /* Remove all reg notes but the REG_DEAD one.  */
+                           REG_NOTES (insn) = trial;
+                           XEXP (trial, 1) = NULL_RTX;
+                         }
+                       else
+#endif
                          delete_insn (insn);
                      }
                  }
                          delete_insn (insn);
                      }
                  }
@@ -499,7 +521,7 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan)
            else if (GET_CODE (body) == PARALLEL)
              {
                /* If each part is a set between two identical registers or
            else if (GET_CODE (body) == PARALLEL)
              {
                /* If each part is a set between two identical registers or
-                  a USE or CLOBBER, delete the insn. */
+                  a USE or CLOBBER, delete the insn.  */
                int i, sreg, dreg;
                rtx tem;
 
                int i, sreg, dreg;
                rtx tem;
 
@@ -841,6 +863,98 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan)
                }
            }
 
                }
            }
 
+         /* Simplify   if (...) { x = a; goto l; } x = b; by converting it
+            to         x = a; if (...) goto l; x = b;
+            if A is sufficiently simple, the test doesn't involve X,
+            and nothing in the test modifies A or X.
+
+            If we have small register classes, we also can't do this if X
+            is a hard register.
+
+            If the "x = a;" insn has any REG_NOTES, we don't do this because
+            of the possibility that we are running after CSE and there is a
+            REG_EQUAL note that is only valid if the branch has already been
+            taken.  If we move the insn with the REG_EQUAL note, we may
+            fold the comparison to always be false in a later CSE pass.
+            (We could also delete the REG_NOTES when moving the insn, but it
+            seems simpler to not move it.)  An exception is that we can move
+            the insn if the only note is a REG_EQUAL or REG_EQUIV whose
+            value is the same as "a".
+
+            INSN is the goto.
+
+            We set:
+
+            TEMP to the jump insn preceding "x = a;"
+            TEMP1 to X
+            TEMP2 to the insn that sets "x = b;"
+            TEMP3 to the insn that sets "x = a;"
+            TEMP4 to the set of "x = a";  */
+
+         if (this_is_simplejump
+             && (temp2 = next_active_insn (insn)) != 0
+             && GET_CODE (temp2) == INSN
+             && (temp4 = single_set (temp2)) != 0
+             && GET_CODE (temp1 = SET_DEST (temp4)) == REG
+#ifdef SMALL_REGISTER_CLASSES
+             && REGNO (temp1) >= FIRST_PSEUDO_REGISTER
+#endif
+
+             && (temp3 = prev_active_insn (insn)) != 0
+             && GET_CODE (temp3) == INSN
+             && (temp4 = single_set (temp3)) != 0
+             && rtx_equal_p (SET_DEST (temp4), temp1)
+             && (GET_CODE (SET_SRC (temp4)) == REG
+                 || GET_CODE (SET_SRC (temp4)) == SUBREG
+                 || CONSTANT_P (SET_SRC (temp4)))
+             && (REG_NOTES (temp3) == 0
+                 || ((REG_NOTE_KIND (REG_NOTES (temp3)) == REG_EQUAL
+                      || REG_NOTE_KIND (REG_NOTES (temp3)) == REG_EQUIV)
+                     && XEXP (REG_NOTES (temp3), 1) == 0
+                     && rtx_equal_p (XEXP (REG_NOTES (temp3), 0),
+                                     SET_SRC (temp4))))
+             && (temp = prev_active_insn (temp3)) != 0
+             && condjump_p (temp) && ! simplejump_p (temp)
+             /* TEMP must skip over the "x = a;" insn */
+             && prev_real_insn (JUMP_LABEL (temp)) == insn
+             && no_labels_between_p (temp, insn))
+           {
+             rtx prev_label = JUMP_LABEL (temp);
+             rtx insert_after = prev_nonnote_insn (temp);
+
+#ifdef HAVE_cc0
+             /* We cannot insert anything between a set of cc and its use.  */
+             if (insert_after && GET_RTX_CLASS (GET_CODE (insert_after)) == 'i'
+                 && sets_cc0_p (PATTERN (insert_after)))
+               insert_after = prev_nonnote_insn (insert_after);
+#endif
+             ++LABEL_NUSES (prev_label);
+
+             if (insert_after
+                 && no_labels_between_p (insert_after, temp)
+                 && ! reg_referenced_between_p (temp1, insert_after, temp3)
+                 && ! reg_referenced_between_p (temp1, temp3,
+                                                NEXT_INSN (temp2))
+                 && ! reg_set_between_p (temp1, insert_after, temp)
+                 && (GET_CODE (SET_SRC (temp4)) == CONST_INT
+                     || ! reg_set_between_p (SET_SRC (temp4),
+                                             insert_after, temp))
+                 && invert_jump (temp, JUMP_LABEL (insn)))
+               {
+                 emit_insn_after_with_line_notes (PATTERN (temp3),
+                                                  insert_after, temp3);
+                 delete_insn (temp3);
+                 delete_insn (insn);
+                 /* Set NEXT to an insn that we know won't go away.  */
+                 next = temp2;
+                 changed = 1;
+               }
+             if (prev_label && --LABEL_NUSES (prev_label) == 0)
+               delete_insn (prev_label);
+             if (changed)
+               continue;
+           }
+
 #ifndef HAVE_cc0
          /* If we have if (...) x = exp;  and branches are expensive,
             EXP is a single insn, does not have any side effects, cannot
 #ifndef HAVE_cc0
          /* If we have if (...) x = exp;  and branches are expensive,
             EXP is a single insn, does not have any side effects, cannot
@@ -943,7 +1057,7 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan)
 
          /* Finally, handle the case where two insns are used to 
             compute EXP but a temporary register is used.  Here we must
 
          /* Finally, handle the case where two insns are used to 
             compute EXP but a temporary register is used.  Here we must
-            ensure that the temporary register is not used anywhere else. */
+            ensure that the temporary register is not used anywhere else.  */
 
          if (! reload_completed
              && after_regscan
 
          if (! reload_completed
              && after_regscan
@@ -1053,13 +1167,9 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan)
                 We could handle BLKmode if (1) emit_store_flag could
                 and (2) we could find the size reliably.  */
              && GET_MODE (XEXP (temp4, 0)) != BLKmode
                 We could handle BLKmode if (1) emit_store_flag could
                 and (2) we could find the size reliably.  */
              && GET_MODE (XEXP (temp4, 0)) != BLKmode
-             /* No point in doing any of this if branches are cheap or we
-                don't have conditional moves.  */
-             && (BRANCH_COST >= 2
-#ifdef HAVE_conditional_move
-                 || 1
-#endif
-                 )
+             /* Even if branches are cheap, the store_flag optimization
+                can win when the operation to be performed can be
+                expressed directly.  */
 #ifdef HAVE_cc0
              /* If the previous insn sets CC0 and something else, we can't
                 do this since we are going to delete that insn.  */
 #ifdef HAVE_cc0
              /* If the previous insn sets CC0 and something else, we can't
                 do this since we are going to delete that insn.  */
@@ -1129,7 +1239,9 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan)
                    end_sequence ();
 
                    emit_insns_before (seq1, temp5);
                    end_sequence ();
 
                    emit_insns_before (seq1, temp5);
-                   emit_insns_before (seq2, insn);
+                   /* Insert conditional move after insn, to be sure that
+                      the jump and a possible compare won't be separated */
+                   emit_insns_after (seq2, insn);
 
                    /* ??? We can also delete the insn that sets X to A.
                       Flow will do it too though.  */
 
                    /* ??? We can also delete the insn that sets X to A.
                       Flow will do it too though.  */
@@ -1168,8 +1280,19 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan)
                     can reverse the condition.  See if (3) applies possibly
                     by reversing the condition.  Prefer reversing to (4) when
                     branches are very expensive.  */
                     can reverse the condition.  See if (3) applies possibly
                     by reversing the condition.  Prefer reversing to (4) when
                     branches are very expensive.  */
-                 && ((reversep = 0, temp2 == const0_rtx)
-                     || (temp3 == const0_rtx
+                 && (((BRANCH_COST >= 2
+                       || STORE_FLAG_VALUE == -1
+                       || (STORE_FLAG_VALUE == 1
+                        /* Check that the mask is a power of two,
+                           so that it can probably be generated
+                           with a shift.  */
+                           && exact_log2 (INTVAL (temp3)) >= 0))
+                      && (reversep = 0, temp2 == const0_rtx))
+                     || ((BRANCH_COST >= 2
+                          || STORE_FLAG_VALUE == -1
+                          || (STORE_FLAG_VALUE == 1
+                              && exact_log2 (INTVAL (temp2)) >= 0))
+                         && temp3 == const0_rtx
                          && (reversep = can_reverse_comparison_p (temp4, insn)))
                      || (BRANCH_COST >= 2
                          && GET_CODE (temp2) == CONST_INT
                          && (reversep = can_reverse_comparison_p (temp4, insn)))
                      || (BRANCH_COST >= 2
                          && GET_CODE (temp2) == CONST_INT
@@ -1924,7 +2047,7 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan)
 
              /* Now that the jump has been tensioned,
                 try cross jumping: check for identical code
 
              /* Now that the jump has been tensioned,
                 try cross jumping: check for identical code
-                before the jump and before its target label. */
+                before the jump and before its target label.  */
 
              /* First, cross jumping of conditional jumps:  */
 
 
              /* First, cross jumping of conditional jumps:  */
 
@@ -1959,7 +2082,7 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan)
                      INSN_CODE (insn) = -1;
                      emit_barrier_after (insn);
                      /* Add to jump_chain unless this is a new label
                      INSN_CODE (insn) = -1;
                      emit_barrier_after (insn);
                      /* Add to jump_chain unless this is a new label
-                        whose UID is too large. */
+                        whose UID is too large.  */
                      if (INSN_UID (JUMP_LABEL (insn)) < max_jump_chain)
                        {
                          jump_chain[INSN_UID (insn)]
                      if (INSN_UID (JUMP_LABEL (insn)) < max_jump_chain)
                        {
                          jump_chain[INSN_UID (insn)]
@@ -2441,13 +2564,13 @@ find_cross_jump (e1, e2, minimum, f1, f2)
 #ifdef STACK_REGS
       /* If cross_jump_death_matters is not 0, the insn's mode
         indicates whether or not the insn contains any stack-like
 #ifdef STACK_REGS
       /* If cross_jump_death_matters is not 0, the insn's mode
         indicates whether or not the insn contains any stack-like
-        regs. */
+        regs.  */
 
       if (!lose && cross_jump_death_matters && GET_MODE (i1) == QImode)
        {
          /* If register stack conversion has already been done, then
             death notes must also be compared before it is certain that
 
       if (!lose && cross_jump_death_matters && GET_MODE (i1) == QImode)
        {
          /* If register stack conversion has already been done, then
             death notes must also be compared before it is certain that
-            the two instruction streams match. */
+            the two instruction streams match.  */
 
          rtx note;
          HARD_REG_SET i1_regset, i2_regset;
 
          rtx note;
          HARD_REG_SET i1_regset, i2_regset;
@@ -4422,7 +4545,7 @@ rtx_equal_for_thread_p (x, y, yinsn)
 
     case MEM:
       /* If memory modified or either volatile, not equivalent.
 
     case MEM:
       /* If memory modified or either volatile, not equivalent.
-        Else, check address. */
+        Else, check address.  */
       if (modified_mem || MEM_VOLATILE_P (x) || MEM_VOLATILE_P (y))
        return 0;
 
       if (modified_mem || MEM_VOLATILE_P (x) || MEM_VOLATILE_P (y))
        return 0;