]> gcc.gnu.org Git - gcc.git/blobdiff - gcc/jump.c
(delete_insn): When deleting after label, delete a BARRIER as well.
[gcc.git] / gcc / jump.c
index f2d4a44de7a3d67cfca4e3a0b516dab9961676c8..c1509647e1704ec0afed875d20dbc0609bd558ad 100644 (file)
@@ -1,5 +1,5 @@
 /* Optimize jump instructions, for GNU compiler.
-   Copyright (C) 1987, 88, 89, 91, 92, 93, 1994 Free Software Foundation, Inc.
+   Copyright (C) 1987, 88, 89, 91-94, 1995 Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
@@ -55,9 +55,9 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #include "flags.h"
 #include "hard-reg-set.h"
 #include "regs.h"
-#include "expr.h"
 #include "insn-config.h"
 #include "insn-flags.h"
+#include "expr.h"
 #include "real.h"
 
 /* ??? Eventually must record somehow the labels used by jumps
@@ -103,19 +103,16 @@ int can_reach_end;
 
 static int cross_jump_death_matters = 0;
 
-static int duplicate_loop_exit_test ();
-void redirect_tablejump ();
-static int delete_labelref_insn ();
-static void mark_jump_label ();
-void delete_jump ();
-void delete_computation ();
-static void delete_from_jump_chain ();
-static int tension_vector_labels ();
-static void find_cross_jump ();
-static void do_cross_jump ();
-static int jump_back_p ();
-
-extern rtx gen_jump ();
+static int duplicate_loop_exit_test    PROTO((rtx));
+static void find_cross_jump            PROTO((rtx, rtx, int, rtx *, rtx *));
+static void do_cross_jump              PROTO((rtx, rtx, rtx));
+static int jump_back_p                 PROTO((rtx, rtx));
+static int tension_vector_labels       PROTO((rtx, int));
+static void mark_jump_label            PROTO((rtx, rtx, int));
+static void delete_computation         PROTO((rtx));
+static void delete_from_jump_chain     PROTO((rtx));
+static int delete_labelref_insn                PROTO((rtx, rtx, int));
+static void redirect_tablejump         PROTO((rtx, rtx));
 \f
 /* Delete no-op jumps and optimize jumps to jumps
    and jumps around jumps.
@@ -143,7 +140,7 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan)
      int noop_moves;
      int after_regscan;
 {
-  register rtx insn, next;
+  register rtx insn, next, note;
   int changed;
   int first = 1;
   int max_uid = 0;
@@ -151,7 +148,8 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan)
 
   cross_jump_death_matters = (cross_jump == 2);
 
-  /* Initialize LABEL_NUSES and JUMP_LABEL fields.  */
+  /* Initialize LABEL_NUSES and JUMP_LABEL fields.  Delete any REG_LABEL
+     notes whose labels don't occur in the insn any more.  */
 
   for (insn = f; insn; insn = NEXT_INSN (insn))
     {
@@ -159,6 +157,15 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan)
        LABEL_NUSES (insn) = (LABEL_PRESERVE_P (insn) != 0);
       else if (GET_CODE (insn) == JUMP_INSN)
        JUMP_LABEL (insn) = 0;
+      else if (GET_CODE (insn) == INSN || GET_CODE (insn) == CALL_INSN)
+       for (note = REG_NOTES (insn); note; note = next)
+         {
+           next = XEXP (note, 1);
+           if (REG_NOTE_KIND (note) == REG_LABEL
+               && ! reg_mentioned_p (XEXP (note, 0), PATTERN (insn)))
+             remove_note (insn, note);
+         }
+
       if (INSN_UID (insn) > max_uid)
        max_uid = INSN_UID (insn);
     }
@@ -190,7 +197,7 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan)
      we make.  */
   max_jump_chain = max_uid * 14 / 10;
   jump_chain = (rtx *) alloca (max_jump_chain * sizeof (rtx));
-  bzero (jump_chain, max_jump_chain * sizeof (rtx));
+  bzero ((char *) jump_chain, max_jump_chain * sizeof (rtx));
 
   /* Mark the label each jump jumps to.
      Combine consecutive labels, and count uses of labels.
@@ -200,8 +207,7 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan)
      also make a chain of all returns.  */
 
   for (insn = f; insn; insn = NEXT_INSN (insn))
-    if ((GET_CODE (insn) == JUMP_INSN || GET_CODE (insn) == INSN
-        || GET_CODE (insn) == CALL_INSN)
+    if (GET_RTX_CLASS (GET_CODE (insn)) == 'i'
        && ! INSN_DELETED_P (insn))
       {
        mark_jump_label (PATTERN (insn), insn, cross_jump);
@@ -356,7 +362,7 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan)
                   maybe eliminate it entirely.  */
                if (total_pushed >= stack_adjust_amount)
                  {
-                   delete_insn (stack_adjust_insn);
+                   delete_computation (stack_adjust_insn);
                    total_pushed = stack_adjust_amount;
                  }
                else
@@ -410,7 +416,7 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan)
                      && MEM_VOLATILE_P (SET_DEST (body)))
                && ! (GET_CODE (SET_SRC (body)) == MEM
                      && MEM_VOLATILE_P (SET_SRC (body))))
-             delete_insn (insn);
+             delete_computation (insn);
 
            /* Detect and ignore no-op move instructions
               resulting from smart or fortuitous register allocation.  */
@@ -510,17 +516,16 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan)
                if (i < 0)
                  delete_insn (insn);
              }
-#if !BYTES_BIG_ENDIAN /* Not worth the hair to detect this
-                        in the big-endian case.  */
            /* Also delete insns to store bit fields if they are no-ops.  */
-           else if (GET_CODE (body) == SET
+           /* Not worth the hair to detect this in the big-endian case.  */
+           else if (! BYTES_BIG_ENDIAN
+                    && GET_CODE (body) == SET
                     && GET_CODE (SET_DEST (body)) == ZERO_EXTRACT
                     && XEXP (SET_DEST (body), 2) == const0_rtx
                     && XEXP (SET_DEST (body), 0) == SET_SRC (body)
                     && ! (GET_CODE (SET_SRC (body)) == MEM
                           && MEM_VOLATILE_P (SET_SRC (body))))
              delete_insn (insn);
-#endif /* not BYTES_BIG_ENDIAN */
          }
       insn = next;
     }
@@ -544,7 +549,8 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan)
               of a reg that's used in notes.  A subsequent optimization
               might arrange to use that reg for real.  */             
            && regno_last_note_uid[REGNO (SET_DEST (set))] == INSN_UID (insn)
-           && ! side_effects_p (SET_SRC (set)))
+           && ! side_effects_p (SET_SRC (set))
+           && ! find_reg_note (insn, REG_RETVAL, 0))
          delete_insn (insn);
       }
 
@@ -560,6 +566,7 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan)
          rtx temp, temp1, temp2, temp3, temp4, temp5, temp6;
          rtx nlabel;
          int this_is_simplejump, this_is_condjump, reversep;
+         int this_is_condjump_in_parallel;
 #if 0
          /* If NOT the first iteration, if this is the last jump pass
             (just before final), do the special peephole optimizations.
@@ -599,6 +606,7 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan)
 
          this_is_simplejump = simplejump_p (insn);
          this_is_condjump = condjump_p (insn);
+         this_is_condjump_in_parallel = condjump_in_parallel_p (insn);
 
          /* Tension the labels in dispatch tables.  */
 
@@ -652,6 +660,7 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan)
          /* Detect jump to following insn.  */
          if (reallabelprev == insn && condjump_p (insn))
            {
+             next = next_real_insn (JUMP_LABEL (insn));
              delete_jump (insn);
              changed = 1;
              continue;
@@ -940,7 +949,11 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan)
                      && simplejump_p (temp2)
                      && JUMP_LABEL (temp2) == JUMP_LABEL (insn)))
              && (temp1 = single_set (temp)) != 0
-             && (temp5 = SET_DEST (temp1), GET_CODE (temp5) == REG)
+             && (temp5 = SET_DEST (temp1),
+                 (GET_CODE (temp5) == REG
+                  || (GET_CODE (temp5) == SUBREG
+                      && (temp5 = SUBREG_REG (temp5),
+                          GET_CODE (temp5) == REG))))
              && REGNO (temp5) >= FIRST_PSEUDO_REGISTER
              && regno_first_uid[REGNO (temp5)] == INSN_UID (temp)
              && regno_last_uid[REGNO (temp5)] == INSN_UID (temp3)
@@ -974,26 +987,23 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan)
            }
 #endif /* HAVE_cc0 */
 
-         /* We deal with four cases:
+         /* Try to use a conditional move (if the target has them), or a
+            store-flag insn.  The general case is:
 
-            1) x = a; if (...) x = b; and either A or B is zero,
-            2) if (...) x = 0; and jumps are expensive,
-            3) x = a; if (...) x = b; and A and B are constants where all the
-               set bits in A are also set in B and jumps are expensive, and
-            4) x = a; if (...) x = b; and A and B non-zero, and jumps are
-               more expensive.
-            5) if (...) x = b; if jumps are even more expensive.
+            1) x = a; if (...) x = b; and
+            2) if (...) x = b;
 
-            In each of these try to use a store-flag insn to avoid the jump.
-            (If the jump would be faster, the machine should not have
-            defined the scc insns!).  These cases are often made by the
+            If the jump would be faster, the machine should not have defined
+            the movcc or scc insns!.  These cases are often made by the
             previous optimization.
 
+            The second case is treated as  x = x; if (...) x = b;.
+
             INSN here is the jump around the store.  We set:
 
             TEMP to the "x = b;" insn.
             TEMP1 to X.
-            TEMP2 to B (const0_rtx in the second case).
+            TEMP2 to B.
             TEMP3 to A (X in the second case).
             TEMP4 to the condition being tested.
             TEMP5 to the earliest insn used to find the condition.  */
@@ -1009,25 +1019,18 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan)
 #ifdef SMALL_REGISTER_CLASSES
              && REGNO (temp1) >= FIRST_PSEUDO_REGISTER
 #endif
-             && GET_MODE_CLASS (GET_MODE (temp1)) == MODE_INT
              && (GET_CODE (temp2 = SET_SRC (PATTERN (temp))) == REG
                  || GET_CODE (temp2) == SUBREG
+                 /* ??? How about floating point constants?  */
                  || GET_CODE (temp2) == CONST_INT)
              /* Allow either form, but prefer the former if both apply. 
                 There is no point in using the old value of TEMP1 if
                 it is a register, since cse will alias them.  It can
                 lose if the old value were a hard register since CSE
                 won't replace hard registers.  */
-             && (((temp3 = reg_set_last (temp1, insn)) != 0
-                  && GET_CODE (temp3) == CONST_INT)
-                 /* Make the latter case look like  x = x; if (...) x = 0;  */
-                 || (temp3 = temp1,
-                     ((BRANCH_COST >= 2
-                       && temp2 == const0_rtx)
-#ifdef HAVE_conditional_move
-                      || 1
-#endif
-                      || BRANCH_COST >= 3)))
+             && (((temp3 = reg_set_last (temp1, insn)) != 0)
+                 /* Make the latter case look like  x = x; if (...) x = b;  */
+                 || (temp3 = temp1, 1))
              /* INSN must either branch to the insn after TEMP or the insn
                 after TEMP must branch to the same place as INSN.  */
              && (reallabelprev == temp
@@ -1039,25 +1042,13 @@ 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
-
-             /* If B is zero, OK; if A is zero, can only do (1) if we
-                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
-                     && (reversep = can_reverse_comparison_p (temp4, insn)))
-                 || (BRANCH_COST >= 2
-                     && GET_CODE (temp2) == CONST_INT
-                     && GET_CODE (temp3) == CONST_INT
-                     && ((INTVAL (temp2) & INTVAL (temp3)) == INTVAL (temp2)
-                         || ((INTVAL (temp2) & INTVAL (temp3)) == INTVAL (temp3)
-                             && (reversep = can_reverse_comparison_p (temp4,
-                                                                      insn)))))
+             /* 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
-                 || BRANCH_COST >= 3)
+                 )
 #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.  */
@@ -1070,139 +1061,245 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan)
 #endif
              )
            {
-             enum rtx_code code = GET_CODE (temp4);
-             rtx uval, cval, var = temp1;
-             int normalizep;
-             rtx target;
-
-             /* If necessary, reverse the condition.  */
-             if (reversep)
-               code = reverse_condition (code), uval = temp2, cval = temp3;
-             else
-               uval = temp3, cval = temp2;
+#ifdef HAVE_conditional_move
+             /* First try a conditional move.  */
+             {
+               enum rtx_code code = GET_CODE (temp4);
+               rtx var = temp1;
+               rtx cond0, cond1, aval, bval;
+               rtx target;
+
+               /* Copy the compared variables into cond0 and cond1, so that
+                  any side effects performed in or after the old comparison,
+                  will not affect our compare which will come later.  */
+               /* ??? Is it possible to just use the comparison in the jump
+                  insn?  After all, we're going to delete it.  We'd have
+                  to modify emit_conditional_move to take a comparison rtx
+                  instead or write a new function.  */
+               cond0 = gen_reg_rtx (GET_MODE (XEXP (temp4, 0)));
+               /* We want the target to be able to simplify comparisons with
+                  zero (and maybe other constants as well), so don't create
+                  pseudos for them.  There's no need to either.  */
+               if (GET_CODE (XEXP (temp4, 1)) == CONST_INT
+                   || GET_CODE (XEXP (temp4, 1)) == CONST_DOUBLE)
+                 cond1 = XEXP (temp4, 1);
+               else
+                 cond1 = gen_reg_rtx (GET_MODE (XEXP (temp4, 1)));
 
-             /* See if we can do this with a store-flag insn. */
-             start_sequence ();
+               aval = temp3;
+               bval = temp2;
 
-             /* If CVAL is non-zero, normalize to -1.  Otherwise,
-                if UVAL is the constant 1, it is best to just compute
-                the result directly.  If UVAL is constant and STORE_FLAG_VALUE
-                includes all of its bits, it is best to compute the flag
-                value unnormalized and `and' it with UVAL.  Otherwise,
-                normalize to -1 and `and' with UVAL.  */
-             normalizep = (cval != const0_rtx ? -1
-                           : (uval == const1_rtx ? 1
-                              : (GET_CODE (uval) == CONST_INT
-                                 && (INTVAL (uval) & ~STORE_FLAG_VALUE) == 0)
-                              ? 0 : -1));
-
-             /* We will be putting the store-flag insn immediately in
-                front of the comparison that was originally being done,
-                so we know all the variables in TEMP4 will be valid.
-                However, this might be in front of the assignment of
-                A to VAR.  If it is, it would clobber the store-flag
-                we will be emitting.
-
-                Therefore, emit into a temporary which will be copied to
-                VAR immediately after TEMP.  */
-
-             target = emit_store_flag (gen_reg_rtx (GET_MODE (var)), code,
-                                       XEXP (temp4, 0), XEXP (temp4, 1),
-                                       VOIDmode,
-                                       (code == LTU || code == LEU 
-                                        || code == GEU || code == GTU),
-                                       normalizep);
-             if (target)
-               {
-                 rtx before = insn;
-                 rtx seq;
+               start_sequence ();
+               target = emit_conditional_move (var, code,
+                                               cond0, cond1, VOIDmode,
+                                               aval, bval, GET_MODE (var),
+                                               (code == LTU || code == GEU
+                                                || code == LEU || code == GTU));
 
-                 /* Put the store-flag insns in front of the first insn
-                    used to compute the condition to ensure that we
-                    use the same values of them as the current 
-                    comparison.  However, the remainder of the insns we
-                    generate will be placed directly in front of the
-                    jump insn, in case any of the pseudos we use
-                    are modified earlier.  */
-
-                 seq = get_insns ();
+               if (target)
+                 {
+                   rtx seq1,seq2;
+
+                   /* Save the conditional move sequence but don't emit it
+                      yet.  On some machines, like the alpha, it is possible
+                      that temp5 == insn, so next generate the sequence that
+                      saves the compared values and then emit both
+                      sequences ensuring seq1 occurs before seq2.  */
+                   seq2 = get_insns ();
+                   end_sequence ();
+
+                   /* Now that we can't fail, generate the copy insns that
+                      preserve the compared values.  */
+                   start_sequence ();
+                   emit_move_insn (cond0, XEXP (temp4, 0));
+                   if (cond1 != XEXP (temp4, 1))
+                     emit_move_insn (cond1, XEXP (temp4, 1));
+                   seq1 = get_insns ();
+                   end_sequence ();
+
+                   emit_insns_before (seq1, temp5);
+                   emit_insns_before (seq2, insn);
+
+                   /* ??? We can also delete the insn that sets X to A.
+                      Flow will do it too though.  */
+                   delete_insn (temp);
+                   next = NEXT_INSN (insn);
+                   delete_jump (insn);
+                   changed = 1;
+                   continue;
+                 }
+               else
                  end_sequence ();
+             }
+#endif
+
+             /* That didn't work, try a store-flag insn.
+
+                We further divide the cases into:
+
+                1) x = a; if (...) x = b; and either A or B is zero,
+                2) if (...) x = 0; and jumps are expensive,
+                3) x = a; if (...) x = b; and A and B are constants where all
+                the set bits in A are also set in B and jumps are expensive,
+                4) x = a; if (...) x = b; and A and B non-zero, and jumps are
+                more expensive, and
+                5) if (...) x = b; if jumps are even more expensive.  */
+
+             if (GET_MODE_CLASS (GET_MODE (temp1)) == MODE_INT
+                 && ((GET_CODE (temp3) == CONST_INT)
+                     /* Make the latter case look like
+                        x = x; if (...) x = 0;  */
+                     || (temp3 = temp1,
+                         ((BRANCH_COST >= 2
+                           && temp2 == const0_rtx)
+                          || BRANCH_COST >= 3)))
+                 /* If B is zero, OK; if A is zero, can only do (1) if we
+                    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
+                         && (reversep = can_reverse_comparison_p (temp4, insn)))
+                     || (BRANCH_COST >= 2
+                         && GET_CODE (temp2) == CONST_INT
+                         && GET_CODE (temp3) == CONST_INT
+                         && ((INTVAL (temp2) & INTVAL (temp3)) == INTVAL (temp2)
+                             || ((INTVAL (temp2) & INTVAL (temp3)) == INTVAL (temp3)
+                                 && (reversep = can_reverse_comparison_p (temp4,
+                                                                          insn)))))
+                     || BRANCH_COST >= 3)
+                 )
+               {
+                 enum rtx_code code = GET_CODE (temp4);
+                 rtx uval, cval, var = temp1;
+                 int normalizep;
+                 rtx target;
 
-                 emit_insns_before (seq, temp5);
+                 /* If necessary, reverse the condition.  */
+                 if (reversep)
+                   code = reverse_condition (code), uval = temp2, cval = temp3;
+                 else
+                   uval = temp3, cval = temp2;
+
+                 /* If CVAL is non-zero, normalize to -1.  Otherwise, if UVAL
+                    is the constant 1, it is best to just compute the result
+                    directly.  If UVAL is constant and STORE_FLAG_VALUE
+                    includes all of its bits, it is best to compute the flag
+                    value unnormalized and `and' it with UVAL.  Otherwise,
+                    normalize to -1 and `and' with UVAL.  */
+                 normalizep = (cval != const0_rtx ? -1
+                               : (uval == const1_rtx ? 1
+                                  : (GET_CODE (uval) == CONST_INT
+                                     && (INTVAL (uval) & ~STORE_FLAG_VALUE) == 0)
+                                  ? 0 : -1));
+
+                 /* We will be putting the store-flag insn immediately in
+                    front of the comparison that was originally being done,
+                    so we know all the variables in TEMP4 will be valid.
+                    However, this might be in front of the assignment of
+                    A to VAR.  If it is, it would clobber the store-flag
+                    we will be emitting.
+
+                    Therefore, emit into a temporary which will be copied to
+                    VAR immediately after TEMP.  */
 
                  start_sequence ();
-
-                 /* Both CVAL and UVAL are non-zero.  */
-                 if (cval != const0_rtx && uval != const0_rtx)
+                 target = emit_store_flag (gen_reg_rtx (GET_MODE (var)), code,
+                                           XEXP (temp4, 0), XEXP (temp4, 1),
+                                           VOIDmode,
+                                           (code == LTU || code == LEU 
+                                            || code == GEU || code == GTU),
+                                           normalizep);
+                 if (target)
                    {
-                     rtx tem1, tem2;
+                     rtx seq;
+                     rtx before = insn;
 
-                     tem1 = expand_and (uval, target, NULL_RTX);
-                     if (GET_CODE (cval) == CONST_INT
-                         && GET_CODE (uval) == CONST_INT
-                         && (INTVAL (cval) & INTVAL (uval)) == INTVAL (cval))
-                       tem2 = cval;
-                     else
-                       {
-                         tem2 = expand_unop (GET_MODE (var), one_cmpl_optab,
-                                             target, NULL_RTX, 0);
-                         tem2 = expand_and (cval, tem2,
-                                            (GET_CODE (tem2) == REG
-                                             ? tem2 : 0));
-                       }
+                     seq = get_insns ();
+                     end_sequence ();
 
-                     /* If we usually make new pseudos, do so here.  This
-                        turns out to help machines that have conditional
-                        move insns.  */
+                     /* Put the store-flag insns in front of the first insn
+                        used to compute the condition to ensure that we
+                        use the same values of them as the current 
+                        comparison.  However, the remainder of the insns we
+                        generate will be placed directly in front of the
+                        jump insn, in case any of the pseudos we use
+                        are modified earlier.  */
 
-                     if (flag_expensive_optimizations)
-                       target = 0;
+                     emit_insns_before (seq, temp5);
 
-                     target = expand_binop (GET_MODE (var), ior_optab,
-                                            tem1, tem2, target,
-                                            1, OPTAB_WIDEN);
-                   }
-                 else if (normalizep != 1)
-                   {
-                     /* We know that either CVAL or UVAL is zero.  If
-                        UVAL is zero, negate TARGET and `and' with CVAL.
-                        Otherwise, `and' with UVAL.  */
-                     if (uval == const0_rtx)
+                     start_sequence ();
+
+                     /* Both CVAL and UVAL are non-zero.  */
+                     if (cval != const0_rtx && uval != const0_rtx)
                        {
-                         target = expand_unop (GET_MODE (var), one_cmpl_optab,
-                                               target, NULL_RTX, 0);
-                         uval = cval;
+                         rtx tem1, tem2;
+
+                         tem1 = expand_and (uval, target, NULL_RTX);
+                         if (GET_CODE (cval) == CONST_INT
+                             && GET_CODE (uval) == CONST_INT
+                             && (INTVAL (cval) & INTVAL (uval)) == INTVAL (cval))
+                           tem2 = cval;
+                         else
+                           {
+                             tem2 = expand_unop (GET_MODE (var), one_cmpl_optab,
+                                                 target, NULL_RTX, 0);
+                             tem2 = expand_and (cval, tem2,
+                                                (GET_CODE (tem2) == REG
+                                                 ? tem2 : 0));
+                           }
+
+                         /* If we usually make new pseudos, do so here.  This
+                            turns out to help machines that have conditional
+                            move insns.  */
+                         /* ??? Conditional moves have already been handled.
+                            This may be obsolete.  */
+
+                         if (flag_expensive_optimizations)
+                           target = 0;
+
+                         target = expand_binop (GET_MODE (var), ior_optab,
+                                                tem1, tem2, target,
+                                                1, OPTAB_WIDEN);
                        }
+                     else if (normalizep != 1)
+                       {
+                         /* We know that either CVAL or UVAL is zero.  If
+                            UVAL is zero, negate TARGET and `and' with CVAL.
+                            Otherwise, `and' with UVAL.  */
+                         if (uval == const0_rtx)
+                           {
+                             target = expand_unop (GET_MODE (var), one_cmpl_optab,
+                                                   target, NULL_RTX, 0);
+                             uval = cval;
+                           }
 
-                     target = expand_and (uval, target,
-                                          (GET_CODE (target) == REG
-                                           && ! preserve_subexpressions_p ()
-                                           ? target : NULL_RTX));
-                   }
+                         target = expand_and (uval, target,
+                                              (GET_CODE (target) == REG
+                                               && ! preserve_subexpressions_p ()
+                                               ? target : NULL_RTX));
+                       }
                  
-                 emit_move_insn (var, target);
-                 seq = get_insns ();
-                 end_sequence ();
-
+                     emit_move_insn (var, target);
+                     seq = get_insns ();
+                     end_sequence ();
 #ifdef HAVE_cc0
-                 /* If INSN uses CC0, we must not separate it from the
-                    insn that sets cc0.  */
-
-                 if (reg_mentioned_p (cc0_rtx, PATTERN (before)))
-                   before = prev_nonnote_insn (before);
+                     /* If INSN uses CC0, we must not separate it from the
+                        insn that sets cc0.  */
+                     if (reg_mentioned_p (cc0_rtx, PATTERN (before)))
+                       before = prev_nonnote_insn (before);
 #endif
+                     emit_insns_before (seq, before);
 
-                 emit_insns_before (seq, before);
-
-                 delete_insn (temp);
-                 next = NEXT_INSN (insn);
-
-                 delete_jump (insn);
-                 changed = 1;
-                 continue;
+                     delete_insn (temp);
+                     next = NEXT_INSN (insn);
+                     delete_jump (insn);
+                     changed = 1;
+                     continue;
+                   }
+                 else
+                   end_sequence ();
                }
-             else
-               end_sequence ();
            }
 
          /* If branches are expensive, convert
@@ -1235,6 +1332,8 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan)
              && (XEXP (SET_SRC (temp1), 1) == const1_rtx
                  || XEXP (SET_SRC (temp1), 1) == constm1_rtx)
              && rtx_equal_p (temp2, XEXP (SET_SRC (temp1), 0))
+             && ! side_effects_p (temp2)
+             && ! may_trap_p (temp2)
              /* INSN must either branch to the insn after TEMP or the insn
                 after TEMP must branch to the same place as INSN.  */
              && (reallabelprev == temp
@@ -1634,7 +1733,8 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan)
            }
          /* Detect a conditional jump jumping over an unconditional jump.  */
 
-         else if (this_is_condjump && ! this_is_simplejump
+         else if ((this_is_condjump || this_is_condjump_in_parallel)
+                  && ! this_is_simplejump
                   && reallabelprev != 0
                   && GET_CODE (reallabelprev) == JUMP_INSN
                   && prev_active_insn (reallabelprev) == insn
@@ -1736,6 +1836,7 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan)
                        rtx range2beg = next_active_insn (label1);
                        rtx range1after, range2after;
                        rtx range1before, range2before;
+                       rtx rangenext;
 
                        /* Include in each range any notes before it, to be
                           sure that we get the line number note if any, even
@@ -1769,6 +1870,41 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan)
                        PREV_INSN (range1beg) = range2before;
                        NEXT_INSN (range1end) = range2after;
                        PREV_INSN (range2after) = range1end;
+
+                       /* Check for a loop end note between the end of
+                          range2, and the next code label.  If there is one,
+                          then what we have really seen is
+                          if (foo) break; end_of_loop;
+                          and moved the break sequence outside the loop.
+                          We must move the LOOP_END note to where the
+                          loop really ends now, or we will confuse loop
+                          optimization.  Stop if we find a LOOP_BEG note
+                          first, since we don't want to move the LOOP_END
+                          note in that case.  */
+                       for (;range2after != label2; range2after = rangenext)
+                         {
+                           rangenext = NEXT_INSN (range2after);
+                           if (GET_CODE (range2after) == NOTE)
+                             {
+                               if (NOTE_LINE_NUMBER (range2after)
+                                   == NOTE_INSN_LOOP_END)
+                                 {
+                                   NEXT_INSN (PREV_INSN (range2after))
+                                     = rangenext;
+                                   PREV_INSN (rangenext)
+                                     = PREV_INSN (range2after);
+                                   PREV_INSN (range2after) 
+                                     = PREV_INSN (range1beg);
+                                   NEXT_INSN (range2after) = range1beg;
+                                   NEXT_INSN (PREV_INSN (range1beg))
+                                     = range2after;
+                                   PREV_INSN (range1beg) = range2after;
+                                 }
+                               else if (NOTE_LINE_NUMBER (range2after)
+                                        == NOTE_INSN_LOOP_BEG)
+                                 break;
+                             }
+                         }
                        changed = 1;
                        continue;
                      }
@@ -1996,8 +2132,8 @@ static int
 duplicate_loop_exit_test (loop_start)
      rtx loop_start;
 {
-  rtx insn, set, p;
-  rtx copy, link;
+  rtx insn, set, reg, p, link;
+  rtx copy = 0;
   int num_insns = 0;
   rtx exitcode = NEXT_INSN (JUMP_LABEL (next_nonnote_insn (loop_start)));
   rtx lastexit;
@@ -2053,12 +2189,14 @@ duplicate_loop_exit_test (loop_start)
   for (insn = exitcode; insn != lastexit; insn = NEXT_INSN (insn))
     if (GET_CODE (insn) == INSN
        && (set = single_set (insn)) != 0
-       && GET_CODE (SET_DEST (set)) == REG
-       && REGNO (SET_DEST (set)) >= FIRST_PSEUDO_REGISTER
-       && regno_first_uid[REGNO (SET_DEST (set))] == INSN_UID (insn))
+       && ((reg = SET_DEST (set), GET_CODE (reg) == REG)
+           || (GET_CODE (reg) == SUBREG
+               && (reg = SUBREG_REG (reg), GET_CODE (reg) == REG)))
+       && REGNO (reg) >= FIRST_PSEUDO_REGISTER
+       && regno_first_uid[REGNO (reg)] == INSN_UID (insn))
       {
        for (p = NEXT_INSN (insn); p != lastexit; p = NEXT_INSN (p))
-         if (regno_last_uid[REGNO (SET_DEST (set))] == INSN_UID (p))
+         if (regno_last_uid[REGNO (reg)] == INSN_UID (p))
            break;
 
        if (p != lastexit)
@@ -2068,13 +2206,12 @@ duplicate_loop_exit_test (loop_start)
            if (reg_map == 0)
              {
                reg_map = (rtx *) alloca (max_reg * sizeof (rtx));
-               bzero (reg_map, max_reg * sizeof (rtx));
+               bzero ((char *) reg_map, max_reg * sizeof (rtx));
              }
 
-           REG_LOOP_TEST_P (SET_DEST (set)) = 1;
+           REG_LOOP_TEST_P (reg) = 1;
 
-           reg_map[REGNO (SET_DEST (set))]
-             = gen_reg_rtx (GET_MODE (SET_DEST (set)));
+           reg_map[REGNO (reg)] = gen_reg_rtx (GET_MODE (reg));
          }
       }
 
@@ -2141,7 +2278,7 @@ duplicate_loop_exit_test (loop_start)
 
   /* Now clean up by emitting a jump to the end label and deleting the jump
      at the start of the loop.  */
-  if (GET_CODE (copy) != BARRIER)
+  if (! copy || GET_CODE (copy) != BARRIER)
     {
       copy = emit_jump_insn_before (gen_jump (get_label_after (insn)),
                                    loop_start);
@@ -2156,11 +2293,11 @@ duplicate_loop_exit_test (loop_start)
       emit_barrier_before (loop_start);
     }
 
-  delete_insn (next_nonnote_insn (loop_start));
-
   /* Mark the exit code as the virtual top of the converted loop.  */
   emit_note_before (NOTE_INSN_LOOP_VTOP, exitcode);
 
+  delete_insn (next_nonnote_insn (loop_start));
+
   return 1;
 }
 \f
@@ -2269,12 +2406,27 @@ find_cross_jump (e1, e2, minimum, f1, f2)
       p1 = PATTERN (i1);
       p2 = PATTERN (i2);
        
+      /* If this is a CALL_INSN, compare register usage information.
+        If we don't check this on stack register machines, the two
+        CALL_INSNs might be merged leaving reg-stack.c with mismatching
+        numbers of stack registers in the same basic block.
+        If we don't check this on machines with delay slots, a delay slot may
+        be filled that clobbers a parameter expected by the subroutine.
+
+        ??? We take the simple route for now and assume that if they're
+        equal, they were constructed identically.  */
+
+      if (GET_CODE (i1) == CALL_INSN
+         && ! rtx_equal_p (CALL_INSN_FUNCTION_USAGE (i1),
+                           CALL_INSN_FUNCTION_USAGE (i2)))
+       lose = 1;
+
 #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. */
 
-      if (cross_jump_death_matters && GET_MODE (i1) == QImode)
+      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
@@ -2368,33 +2520,6 @@ find_cross_jump (e1, e2, minimum, f1, f2)
        }
     }
 
-  /* We have to be careful that we do not cross-jump into the middle of
-     USE-CALL_INSN-CLOBBER sequence.  This sequence is used instead of
-     putting the USE and CLOBBERs inside the CALL_INSN.  The delay slot
-     scheduler needs to know what registers are used and modified by the
-     CALL_INSN and needs the adjacent USE and CLOBBERs to do so.
-
-     ??? At some point we should probably change this so that these are
-     part of the CALL_INSN.  The way we are doing it now is a kludge that
-     is now causing trouble.  */
-
-  if (last1 != 0 && GET_CODE (last1) == CALL_INSN
-      && (prev1 = prev_nonnote_insn (last1))
-      && GET_CODE (prev1) == INSN
-      && GET_CODE (PATTERN (prev1)) == USE)
-    {
-      /* Remove this CALL_INSN from the range we can cross-jump.  */
-      last1 = next_real_insn (last1);
-      last2 = next_real_insn (last2);
-
-      minimum++;
-    }
-
-  /* Skip past CLOBBERS since they may be right after a CALL_INSN.  It
-     isn't worth checking for the CALL_INSN.  */
-  while (last1 != 0 && GET_CODE (PATTERN (last1)) == CLOBBER)
-    last1 = next_real_insn (last1), last2 = next_real_insn (last2);
-
   if (minimum <= 0 && last1 != 0 && last1 != e1)
     *f1 = last1, *f2 = last2;
 }
@@ -2465,15 +2590,6 @@ get_label_before (insn)
     {
       rtx prev = PREV_INSN (insn);
 
-      /* Don't put a label between a CALL_INSN and USE insns that precede
-        it.  */
-
-      if (GET_CODE (insn) == CALL_INSN
-         || (GET_CODE (insn) == INSN && GET_CODE (PATTERN (insn)) == SEQUENCE
-             && GET_CODE (XVECEXP (PATTERN (insn), 0, 0)) == CALL_INSN))
-       while (GET_CODE (prev) == INSN && GET_CODE (PATTERN (prev)) == USE)
-         prev = PREV_INSN (prev);
-
       label = gen_label_rtx ();
       emit_label_after (label, prev);
       LABEL_NUSES (label) = 0;
@@ -2495,16 +2611,6 @@ get_label_after (insn)
 
   if (label == 0 || GET_CODE (label) != CODE_LABEL)
     {
-      /* Don't put a label between a CALL_INSN and CLOBBER insns
-        following it. */
-
-      if (GET_CODE (insn) == CALL_INSN
-         || (GET_CODE (insn) == INSN && GET_CODE (PATTERN (insn)) == SEQUENCE
-             && GET_CODE (XVECEXP (PATTERN (insn), 0, 0)) == CALL_INSN))
-       while (GET_CODE (NEXT_INSN (insn)) == INSN
-              && GET_CODE (PATTERN (NEXT_INSN (insn))) == CLOBBER)
-         insn = NEXT_INSN (insn);
-
       label = gen_label_rtx ();
       emit_label_after (label, insn);
       LABEL_NUSES (label) = 0;
@@ -2851,6 +2957,39 @@ condjump_p (insn)
   return 0;
 }
 
+/* Return nonzero if INSN is a (possibly) conditional jump
+   and nothing more.  */
+
+int
+condjump_in_parallel_p (insn)
+     rtx insn;
+{
+  register rtx x = PATTERN (insn);
+
+  if (GET_CODE (x) != PARALLEL)
+    return 0;
+  else
+    x = XVECEXP (x, 0, 0);
+
+  if (GET_CODE (x) != SET)
+    return 0;
+  if (GET_CODE (SET_DEST (x)) != PC)
+    return 0;
+  if (GET_CODE (SET_SRC (x)) == LABEL_REF)
+    return 1;
+  if (GET_CODE (SET_SRC (x)) != IF_THEN_ELSE)
+    return 0;
+  if (XEXP (SET_SRC (x), 2) == pc_rtx
+      && (GET_CODE (XEXP (SET_SRC (x), 1)) == LABEL_REF
+         || GET_CODE (XEXP (SET_SRC (x), 1)) == RETURN))
+    return 1;
+  if (XEXP (SET_SRC (x), 1) == pc_rtx
+      && (GET_CODE (XEXP (SET_SRC (x), 2)) == LABEL_REF
+         || GET_CODE (XEXP (SET_SRC (x), 2)) == RETURN))
+    return 1;
+  return 0;
+}
+
 /* Return 1 if X is an RTX that does nothing but set the condition codes
    and CLOBBER or USE registers.
    Return -1 if X does explicitly set the condition codes,
@@ -3071,13 +3210,8 @@ mark_jump_label (x, insn, cross_jump)
                    || ! (GET_CODE (next) == JUMP_INSN
                          && (GET_CODE (PATTERN (next)) == ADDR_VEC
                              || GET_CODE (PATTERN (next)) == ADDR_DIFF_VEC)))
-                 {
-                   REG_NOTES (insn) = gen_rtx (EXPR_LIST, REG_LABEL, label,
-                                               REG_NOTES (insn));
-                   /* Record in the note whether label is nonlocal.  */
-                   LABEL_REF_NONLOCAL_P (REG_NOTES (insn))
-                     = LABEL_REF_NONLOCAL_P (x);
-                 }
+                 REG_NOTES (insn) = gen_rtx (EXPR_LIST, REG_LABEL, label,
+                                             REG_NOTES (insn));
              }
          }
        return;
@@ -3137,7 +3271,7 @@ delete_jump (insn)
    On machines with CC0, if CC0 is used in this insn, we may be able to
    delete the insn that set it.  */
 
-void
+static void
 delete_computation (insn)
      rtx insn;
 {
@@ -3331,6 +3465,24 @@ delete_insn (insn)
        return next;
       }
 
+  /* Likewise if we're deleting a dispatch table.  */
+
+  if (GET_CODE (insn) == JUMP_INSN
+      && (GET_CODE (PATTERN (insn)) == ADDR_VEC
+         || GET_CODE (PATTERN (insn)) == ADDR_DIFF_VEC))
+    {
+      rtx pat = PATTERN (insn);
+      int i, diff_vec_p = GET_CODE (pat) == ADDR_DIFF_VEC;
+      int len = XVECLEN (pat, diff_vec_p);
+
+      for (i = 0; i < len; i++)
+       if (--LABEL_NUSES (XEXP (XVECEXP (pat, diff_vec_p, i), 0)) == 0)
+         delete_insn (XEXP (XVECEXP (pat, diff_vec_p, i), 0));
+      while (next && INSN_DELETED_P (next))
+       next = NEXT_INSN (next);
+      return next;
+    }
+
   while (prev && (INSN_DELETED_P (prev) || GET_CODE (prev) == NOTE))
     prev = PREV_INSN (prev);
 
@@ -3351,9 +3503,8 @@ delete_insn (insn)
     {
       register RTX_CODE code;
       while (next != 0
-            && ((code = GET_CODE (next)) == INSN
-                || code == JUMP_INSN || code == CALL_INSN
-                || code == NOTE
+            && (GET_RTX_CLASS (code = GET_CODE (next)) == 'i'
+                || code == NOTE || code == BARRIER
                 || (code == CODE_LABEL && INSN_DELETED_P (next))))
        {
          if (code == NOTE
@@ -3434,8 +3585,6 @@ int
 invert_jump (jump, nlabel)
      rtx jump, nlabel;
 {
-  register rtx olabel = JUMP_LABEL (jump);
-
   /* We have to either invert the condition and change the label or
      do neither.  Either operation could fail.  We first try to invert
      the jump. If that succeeds, we try changing the label.  If that fails,
@@ -3667,7 +3816,7 @@ redirect_exp (loc, olabel, nlabel, insn)
    before the jump references that label and delete it and logical successors
    too.  */
 
-void
+static void
 redirect_tablejump (jump, nlabel)
      rtx jump, nlabel;
 {
@@ -4044,7 +4193,8 @@ thread_jumps (f, max_reg, flag_before_loop)
          bzero (modified_regs, max_reg * sizeof (char));
          modified_mem = 0;
 
-         bcopy (all_reset, same_regs, max_reg * sizeof (int));
+         bcopy ((char *) all_reset, (char *) same_regs,
+                max_reg * sizeof (int));
          num_same_regs = 0;
 
          label = JUMP_LABEL (b1);
@@ -4207,6 +4357,19 @@ rtx_equal_for_thread_p (x, y, yinsn)
   if (GET_MODE (x) != GET_MODE (y))
     return 0;
 
+  /* For commutative operations, the RTX match if the operand match in any
+     order.  Also handle the simple binary and unary cases without a loop.  */
+  if (code == EQ || code == NE || GET_RTX_CLASS (code) == 'c')
+    return ((rtx_equal_for_thread_p (XEXP (x, 0), XEXP (y, 0), yinsn)
+            && rtx_equal_for_thread_p (XEXP (x, 1), XEXP (y, 1), yinsn))
+           || (rtx_equal_for_thread_p (XEXP (x, 0), XEXP (y, 1), yinsn)
+               && rtx_equal_for_thread_p (XEXP (x, 1), XEXP (y, 0), yinsn)));
+  else if (GET_RTX_CLASS (code) == '<' || GET_RTX_CLASS (code) == '2')
+    return (rtx_equal_for_thread_p (XEXP (x, 0), XEXP (y, 0), yinsn)
+           && rtx_equal_for_thread_p (XEXP (x, 1), XEXP (y, 1), yinsn));
+  else if (GET_RTX_CLASS (code) == '1')
+    return rtx_equal_for_thread_p (XEXP (x, 0), XEXP (y, 0), yinsn);
+
   /* Handle special-cases first.  */
   switch (code)
     {
This page took 0.056303 seconds and 5 git commands to generate.