OSDN Git Service

[pf3gnuchains/gcc-fork.git] / gcc / combine.c
index 619c897..bd0a225 100644 (file)
@@ -426,7 +426,7 @@ static int merge_outer_ops  PROTO((enum rtx_code *, HOST_WIDE_INT *,
                                       enum machine_mode, int *));
 static rtx simplify_shift_const        PROTO((rtx, enum rtx_code, enum machine_mode,
                                       rtx, int));
-static int recog_for_combine   PROTO((rtx *, rtx, rtx *, int *));
+static int recog_for_combine   PROTO((rtx *, rtx, rtx *));
 static rtx gen_lowpart_for_combine  PROTO((enum machine_mode, rtx));
 static rtx gen_rtx_combine PVPROTO((enum rtx_code code, enum machine_mode mode,
                                  ...));
@@ -674,6 +674,9 @@ combine_instructions (f, nregs)
   total_successes += combine_successes;
 
   nonzero_sign_valid = 0;
+
+  /* Make recognizer allow volatile MEMs again.  */
+  init_recog ();
 }
 
 /* Wipe the reg_last_xxx arrays in preparation for another pass.  */
@@ -1353,8 +1356,6 @@ try_combine (i3, i2, i1)
   int i3_subst_into_i2 = 0;
   /* Notes that I1, I2 or I3 is a MULT operation.  */
   int have_mult = 0;
-  /* Number of clobbers of SCRATCH we had to add.  */
-  int i3_scratches = 0, i2_scratches = 0, other_scratches = 0;
 
   int maxreg;
   rtx temp;
@@ -1831,8 +1832,7 @@ try_combine (i3, i2, i1)
   mark_used_regs_combine (newpat);
 
   /* Is the result of combination a valid instruction?  */
-  insn_code_number
-    = recog_for_combine (&newpat, i3, &new_i3_notes, &i3_scratches);
+  insn_code_number = recog_for_combine (&newpat, i3, &new_i3_notes);
 
   /* If the result isn't valid, see if it is a PARALLEL of two SETs where
      the second SET's destination is a register that is unused.  In that case,
@@ -1853,8 +1853,7 @@ try_combine (i3, i2, i1)
       && asm_noperands (newpat) < 0)
     {
       newpat = XVECEXP (newpat, 0, 0);
-      insn_code_number
-       = recog_for_combine (&newpat, i3, &new_i3_notes, &i3_scratches);
+      insn_code_number = recog_for_combine (&newpat, i3, &new_i3_notes);
     }
 
   else if (insn_code_number < 0 && GET_CODE (newpat) == PARALLEL
@@ -1867,8 +1866,7 @@ try_combine (i3, i2, i1)
           && asm_noperands (newpat) < 0)
     {
       newpat = XVECEXP (newpat, 0, 1);
-      insn_code_number
-       = recog_for_combine (&newpat, i3, &new_i3_notes, &i3_scratches);
+      insn_code_number = recog_for_combine (&newpat, i3, &new_i3_notes);
     }
 
   /* If we were combining three insns and the result is a simple SET
@@ -1937,8 +1935,7 @@ try_combine (i3, i2, i1)
          if (REGNO (i2dest) >= FIRST_PSEUDO_REGISTER)
            SUBST (regno_reg_rtx[REGNO (i2dest)], ni2dest);
 
-         i2_code_number = recog_for_combine (&newi2pat, i2, &new_i2_notes,
-                                             &i2_scratches);
+         i2_code_number = recog_for_combine (&newi2pat, i2, &new_i2_notes);
 
          /* If I2 or I3 has multiple SETs, we won't know how to track
             register status, so don't use these insns.  If I2's destination
@@ -1947,8 +1944,8 @@ try_combine (i3, i2, i1)
          if (i2_code_number >= 0 && i2set && i3set
              && (next_real_insn (i2) == i3
                  || ! reg_used_between_p (SET_DEST (i2set), i2, i3)))
-           insn_code_number = recog_for_combine (&newi3pat, i3, &new_i3_notes,
-                                                 &i3_scratches); 
+           insn_code_number = recog_for_combine (&newi3pat, i3,
+                                                 &new_i3_notes);
          if (insn_code_number >= 0)
            newpat = newi3pat;
 
@@ -2035,14 +2032,12 @@ try_combine (i3, i2, i1)
 
          newi2pat = gen_rtx_combine (SET, VOIDmode, newdest, *split);
          SUBST (*split, newdest);
-         i2_code_number
-           = recog_for_combine (&newi2pat, i2, &new_i2_notes, &i2_scratches);
+         i2_code_number = recog_for_combine (&newi2pat, i2, &new_i2_notes);
 
          /* If the split point was a MULT and we didn't have one before,
             don't use one now.  */
          if (i2_code_number >= 0 && ! (split_code == MULT && ! have_mult))
-           insn_code_number
-             = recog_for_combine (&newpat, i3, &new_i3_notes, &i3_scratches);
+           insn_code_number = recog_for_combine (&newpat, i3, &new_i3_notes);
        }
     }
 
@@ -2096,12 +2091,10 @@ try_combine (i3, i2, i1)
       newpat = XVECEXP (newpat, 0, 1);
       SUBST (SET_SRC (newpat),
             gen_lowpart_for_combine (GET_MODE (SET_SRC (newpat)), ni2dest));
-      i2_code_number
-       = recog_for_combine (&newi2pat, i2, &new_i2_notes, &i2_scratches);
+      i2_code_number = recog_for_combine (&newi2pat, i2, &new_i2_notes);
 
       if (i2_code_number >= 0)
-       insn_code_number
-         = recog_for_combine (&newpat, i3, &new_i3_notes, &i3_scratches);
+       insn_code_number = recog_for_combine (&newpat, i3, &new_i3_notes);
 
       if (insn_code_number >= 0)
        {
@@ -2188,12 +2181,10 @@ try_combine (i3, i2, i1)
          newpat = XVECEXP (newpat, 0, 0);
        }
 
-      i2_code_number
-       = recog_for_combine (&newi2pat, i2, &new_i2_notes, &i2_scratches);
+      i2_code_number = recog_for_combine (&newi2pat, i2, &new_i2_notes);
 
       if (i2_code_number >= 0)
-       insn_code_number
-         = recog_for_combine (&newpat, i3, &new_i3_notes, &i3_scratches);
+       insn_code_number = recog_for_combine (&newpat, i3, &new_i3_notes);
     }
 
   /* If it still isn't recognized, fail and change things back the way they
@@ -2215,9 +2206,8 @@ try_combine (i3, i2, i1)
 
       CLEAR_HARD_REG_SET (newpat_used_regs);
 
-      other_code_number
-       = recog_for_combine (&other_pat, undobuf.other_insn,
-                            &new_other_notes, &other_scratches);
+      other_code_number = recog_for_combine (&other_pat, undobuf.other_insn,
+                                            &new_other_notes);
 
       if (other_code_number < 0 && ! check_asm_operands (other_pat))
        {
@@ -2534,12 +2524,6 @@ try_combine (i3, i2, i1)
     if (newi2pat)
       note_stores (newi2pat, set_nonzero_bits_and_sign_copies);
 
-    /* If we added any (clobber (scratch)), add them to the max for a
-       block.  This is a very pessimistic calculation, since we might
-       have had them already and this might not be the worst block, but
-       it's not worth doing any better.  */
-    max_scratch += i3_scratches + i2_scratches + other_scratches;
-
     /* If I3 is now an unconditional jump, ensure that it has a 
        BARRIER following it since it may have initially been a
        conditional jump.  It may also be the last nonnote insn.  */
@@ -3064,103 +3048,154 @@ subst (x, from, to, in_dest, unique_copy)
   if (COMBINE_RTX_EQUAL_P (x, to))
     return to;
 
-  len = GET_RTX_LENGTH (code);
-  fmt = GET_RTX_FORMAT (code);
+  /* Parallel asm_operands need special attention because all of the
+     inputs are shared across the arms.  Furthermore, unsharing the
+     rtl results in recognition failures.  Failure to handle this case
+     specially can result in circular rtl.
 
-  /* We don't need to process a SET_DEST that is a register, CC0, or PC, so
-     set up to skip this common case.  All other cases where we want to
-     suppress replacing something inside a SET_SRC are handled via the
-     IN_DEST operand.  */
-  if (code == SET
-      && (GET_CODE (SET_DEST (x)) == REG
-        || GET_CODE (SET_DEST (x)) == CC0
-        || GET_CODE (SET_DEST (x)) == PC))
-    fmt = "ie";
-
-  /* Get the mode of operand 0 in case X is now a SIGN_EXTEND of a
-     constant.  */
-  if (fmt[0] == 'e')
-    op0_mode = GET_MODE (XEXP (x, 0));
+     Solve this by doing a normal pass across the first entry of the
+     parallel, and only processing the SET_DESTs of the subsequent
+     entries.  Ug.  */
 
-  for (i = 0; i < len; i++)
+  if (code == PARALLEL
+      && GET_CODE (XVECEXP (x, 0, 0)) == SET
+      && GET_CODE (SET_SRC (XVECEXP (x, 0, 0))) == ASM_OPERANDS)
     {
-      if (fmt[i] == 'E')
+      new = subst (XVECEXP (x, 0, 0), from, to, 0, unique_copy);
+
+      /* If this substitution failed, this whole thing fails.  */
+      if (GET_CODE (new) == CLOBBER
+         && XEXP (new, 0) == const0_rtx)
+       return new;
+
+      SUBST (XVECEXP (x, 0, 0), new);
+
+      for (i = XVECLEN (x, 0) - 1; i >= 1; i--)
        {
-         register int j;
-         for (j = XVECLEN (x, i) - 1; j >= 0; j--)
+         rtx dest = SET_DEST (XVECEXP (x, 0, i));
+         
+         if (GET_CODE (dest) != REG
+             && GET_CODE (dest) != CC0
+             && GET_CODE (dest) != PC)
            {
-             if (COMBINE_RTX_EQUAL_P (XVECEXP (x, i, j), from))
-               {
-                 new = (unique_copy && n_occurrences ? copy_rtx (to) : to);
-                 n_occurrences++;
-               }
-             else
-               {
-                 new = subst (XVECEXP (x, i, j), from, to, 0, unique_copy);
+             new = subst (dest, from, to, 0, unique_copy);
 
-                 /* If this substitution failed, this whole thing fails.  */
-                 if (GET_CODE (new) == CLOBBER && XEXP (new, 0) == const0_rtx)
-                   return new;
-               }
+             /* If this substitution failed, this whole thing fails.  */
+             if (GET_CODE (new) == CLOBBER
+                 && XEXP (new, 0) == const0_rtx)
+               return new;
 
-             SUBST (XVECEXP (x, i, j), new);
+             SUBST (SET_DEST (XVECEXP (x, 0, i)), new);
            }
        }
-      else if (fmt[i] == 'e')
+    }
+  else
+    {
+      len = GET_RTX_LENGTH (code);
+      fmt = GET_RTX_FORMAT (code);
+
+      /* We don't need to process a SET_DEST that is a register, CC0,
+        or PC, so set up to skip this common case.  All other cases
+        where we want to suppress replacing something inside a
+        SET_SRC are handled via the IN_DEST operand.  */
+      if (code == SET
+         && (GET_CODE (SET_DEST (x)) == REG
+             || GET_CODE (SET_DEST (x)) == CC0
+             || GET_CODE (SET_DEST (x)) == PC))
+       fmt = "ie";
+
+      /* Get the mode of operand 0 in case X is now a SIGN_EXTEND of a
+        constant.  */
+      if (fmt[0] == 'e')
+       op0_mode = GET_MODE (XEXP (x, 0));
+
+      for (i = 0; i < len; i++)
        {
-         if (COMBINE_RTX_EQUAL_P (XEXP (x, i), from))
+         if (fmt[i] == 'E')
+           {
+             register int j;
+             for (j = XVECLEN (x, i) - 1; j >= 0; j--)
+               {
+                 if (COMBINE_RTX_EQUAL_P (XVECEXP (x, i, j), from))
+                   {
+                     new = (unique_copy && n_occurrences
+                            ? copy_rtx (to) : to);
+                     n_occurrences++;
+                   }
+                 else
+                   {
+                     new = subst (XVECEXP (x, i, j), from, to, 0,
+                                  unique_copy);
+
+                     /* If this substitution failed, this whole thing
+                        fails.  */
+                     if (GET_CODE (new) == CLOBBER
+                         && XEXP (new, 0) == const0_rtx)
+                       return new;
+                   }
+
+                 SUBST (XVECEXP (x, i, j), new);
+               }
+           }
+         else if (fmt[i] == 'e')
            {
-             /* In general, don't install a subreg involving two modes not
-                tieable.  It can worsen register allocation, and can even
-                make invalid reload insns, since the reg inside may need to
-                be copied from in the outside mode, and that may be invalid
-                if it is an fp reg copied in integer mode.
-
-                We allow two exceptions to this: It is valid if it is inside
-                another SUBREG and the mode of that SUBREG and the mode of
-                the inside of TO is tieable and it is valid if X is a SET
-                that copies FROM to CC0.  */
-             if (GET_CODE (to) == SUBREG
-                 && ! MODES_TIEABLE_P (GET_MODE (to),
-                                       GET_MODE (SUBREG_REG (to)))
-                 && ! (code == SUBREG
-                       && MODES_TIEABLE_P (GET_MODE (x),
-                                           GET_MODE (SUBREG_REG (to))))
+             if (COMBINE_RTX_EQUAL_P (XEXP (x, i), from))
+               {
+                 /* In general, don't install a subreg involving two
+                    modes not tieable.  It can worsen register
+                    allocation, and can even make invalid reload
+                    insns, since the reg inside may need to be copied
+                    from in the outside mode, and that may be invalid
+                    if it is an fp reg copied in integer mode.
+
+                    We allow two exceptions to this: It is valid if
+                    it is inside another SUBREG and the mode of that
+                    SUBREG and the mode of the inside of TO is
+                    tieable and it is valid if X is a SET that copies
+                    FROM to CC0.  */
+
+                 if (GET_CODE (to) == SUBREG
+                     && ! MODES_TIEABLE_P (GET_MODE (to),
+                                           GET_MODE (SUBREG_REG (to)))
+                     && ! (code == SUBREG
+                           && MODES_TIEABLE_P (GET_MODE (x),
+                                               GET_MODE (SUBREG_REG (to))))
 #ifdef HAVE_cc0
-                 && ! (code == SET && i == 1 && XEXP (x, 0) == cc0_rtx)
+                     && ! (code == SET && i == 1 && XEXP (x, 0) == cc0_rtx)
 #endif
-                 )
-               return gen_rtx_CLOBBER (VOIDmode, const0_rtx);
+                     )
+                   return gen_rtx_CLOBBER (VOIDmode, const0_rtx);
 
-             new = (unique_copy && n_occurrences ? copy_rtx (to) : to);
-             n_occurrences++;
+                 new = (unique_copy && n_occurrences ? copy_rtx (to) : to);
+                 n_occurrences++;
+               }
+             else
+               /* If we are in a SET_DEST, suppress most cases unless we
+                  have gone inside a MEM, in which case we want to
+                  simplify the address.  We assume here that things that
+                  are actually part of the destination have their inner
+                  parts in the first expression.  This is true for SUBREG, 
+                  STRICT_LOW_PART, and ZERO_EXTRACT, which are the only
+                  things aside from REG and MEM that should appear in a
+                  SET_DEST.  */
+               new = subst (XEXP (x, i), from, to,
+                            (((in_dest
+                               && (code == SUBREG || code == STRICT_LOW_PART
+                                   || code == ZERO_EXTRACT))
+                              || code == SET)
+                             && i == 0), unique_copy);
+
+             /* If we found that we will have to reject this combination,
+                indicate that by returning the CLOBBER ourselves, rather than
+                an expression containing it.  This will speed things up as
+                well as prevent accidents where two CLOBBERs are considered
+                to be equal, thus producing an incorrect simplification.  */
+
+             if (GET_CODE (new) == CLOBBER && XEXP (new, 0) == const0_rtx)
+               return new;
+
+             SUBST (XEXP (x, i), new);
            }
-         else
-           /* If we are in a SET_DEST, suppress most cases unless we
-              have gone inside a MEM, in which case we want to
-              simplify the address.  We assume here that things that
-              are actually part of the destination have their inner
-              parts in the first expression.  This is true for SUBREG, 
-              STRICT_LOW_PART, and ZERO_EXTRACT, which are the only
-              things aside from REG and MEM that should appear in a
-              SET_DEST.  */
-           new = subst (XEXP (x, i), from, to,
-                        (((in_dest
-                           && (code == SUBREG || code == STRICT_LOW_PART
-                               || code == ZERO_EXTRACT))
-                          || code == SET)
-                         && i == 0), unique_copy);
-
-         /* If we found that we will have to reject this combination,
-            indicate that by returning the CLOBBER ourselves, rather than
-            an expression containing it.  This will speed things up as
-            well as prevent accidents where two CLOBBERs are considered
-            to be equal, thus producing an incorrect simplification.  */
-
-         if (GET_CODE (new) == CLOBBER && XEXP (new, 0) == const0_rtx)
-           return new;
-
-         SUBST (XEXP (x, i), new);
        }
     }
 
@@ -4648,9 +4683,8 @@ simplify_set (x)
              && exact_log2 (mask = nonzero_bits (op0, GET_MODE (op0))) >= 0)
            {
              rtx pat = PATTERN (other_insn), note = 0;
-             int scratches;
 
-             if ((recog_for_combine (&pat, other_insn, &note, &scratches) < 0
+             if ((recog_for_combine (&pat, other_insn, &note) < 0
                   && ! check_asm_operands (pat)))
                {
                  PUT_CODE (*cc_use, old_code);
@@ -9049,18 +9083,14 @@ simplify_shift_const (x, code, result_mode, varop, count)
    PNOTES is a pointer to a location where any REG_UNUSED notes added for
    the CLOBBERs are placed.
 
-   PADDED_SCRATCHES is set to the number of (clobber (scratch)) patterns
-   we had to add.
-
    The value is the final insn code from the pattern ultimately matched,
    or -1.  */
 
 static int
-recog_for_combine (pnewpat, insn, pnotes, padded_scratches)
+recog_for_combine (pnewpat, insn, pnotes)
      rtx *pnewpat;
      rtx insn;
      rtx *pnotes;
-     int *padded_scratches;
 {
   register rtx pat = *pnewpat;
   int insn_code_number;
@@ -9068,8 +9098,6 @@ recog_for_combine (pnewpat, insn, pnotes, padded_scratches)
   int i;
   rtx notes = 0;
 
-  *padded_scratches = 0;
-
   /* If PAT is a PARALLEL, check to see if it contains the CLOBBER
      we use to indicate that something didn't match.  If we find such a
      thing, force rejection.  */
@@ -9131,8 +9159,6 @@ recog_for_combine (pnewpat, insn, pnotes, padded_scratches)
          if (GET_CODE (XEXP (XVECEXP (newpat, 0, i), 0)) == REG
              && ! reg_dead_at_p (XEXP (XVECEXP (newpat, 0, i), 0), insn))
            return -1;
-         else if (GET_CODE (XEXP (XVECEXP (newpat, 0, i), 0)) == SCRATCH)
-           (*padded_scratches)++;
          notes = gen_rtx_EXPR_LIST (REG_UNUSED,
                                     XEXP (XVECEXP (newpat, 0, i), 0), notes);
        }
@@ -9262,7 +9288,7 @@ gen_lowpart_for_combine (mode, x)
 static rtx
 gen_rtx_combine VPROTO((enum rtx_code code, enum machine_mode mode, ...))
 {
-#ifndef __STDC__
+#ifndef ANSI_PROTOTYPES
   enum rtx_code code;
   enum machine_mode mode;
 #endif
@@ -9276,7 +9302,7 @@ gen_rtx_combine VPROTO((enum rtx_code code, enum machine_mode mode, ...))
 
   VA_START (p, mode);
 
-#ifndef __STDC__
+#ifndef ANSI_PROTOTYPES
   code = va_arg (p, enum rtx_code);
   mode = va_arg (p, enum machine_mode);
 #endif